Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add median, median_low and median_high aggregation methods #339

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Options:
--aggregationMethod=AGGREGATIONMETHOD
The consolidation function to fetch from on input and
aggregationMethod to set on output. One of: average,
last, max, min, avg_zero, absmax, absmin
last, max, min, avg_zero, absmax, absmin, median,
median_low, median_high
--destinationPath=DESTINATIONPATH
Path to place created whisper file. Defaults to the
RRD file's source path.
Expand Down Expand Up @@ -66,7 +67,8 @@ Options:
--xFilesFactor=XFILESFACTOR
--aggregationMethod=AGGREGATIONMETHOD
Function to use when aggregating values (average, sum,
last, max, min, avg_zero, absmax, absmin)
last, max, min, avg_zero, absmax, absmin, median,
median_low, median_high)
--overwrite
--estimate Don't create a whisper file, estimate storage requirements based on archive definitions
```
Expand Down Expand Up @@ -170,7 +172,8 @@ Options:
Change the xFilesFactor
--aggregationMethod=AGGREGATIONMETHOD
Change the aggregation function (average, sum, last,
max, min, avg_zero, absmax, absmin)
max, min, avg_zero, absmax, absmin, median,
median_low, median_high)
--force Perform a destructive change
--newfile=NEWFILE Create a new database file without removing the
existing one
Expand All @@ -185,7 +188,7 @@ whisper-set-aggregation-method.py
Change the aggregation method of an existing whisper file.

```
Usage: whisper-set-aggregation-method.py path <average|sum|last|max|min|avg_zero|absmax|absmin>
Usage: whisper-set-aggregation-method.py path <average|sum|last|max|min|avg_zero|absmax|absmin|median|median_low|median_high>

Options:
-h, --help show this help message and exit
Expand Down
6 changes: 6 additions & 0 deletions bin/rrd2whisper.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
aggregationMethods.remove('absmax')
# RRD doesn't have a 'absmin' type
aggregationMethods.remove('absmin')
# RRD doesn't have a 'median' type
aggregationMethods.remove('median')
# RRD doesn't have a 'median_low' type
aggregationMethods.remove('median_low')
# RRD doesn't have a 'median_high' type
aggregationMethods.remove('median_high')

option_parser = optparse.OptionParser(usage='''%prog rrd_path''')
option_parser.add_option(
Expand Down
8 changes: 8 additions & 0 deletions test_whisper.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,14 @@ def test_aggregate(self):
self.assertEqual(whisper.aggregate('absmin', [-3, -2, 1, 2]), 1)
# absmin with negative min
self.assertEqual(whisper.aggregate('absmin', [-2, -1, 2, 3]), -1)
# median with odd number of values
self.assertEqual(whisper.aggregate('median', [10, 1, 12, 42, 7]), 10)
# median with even number of values
self.assertEqual(whisper.aggregate('median', [9, 2, 5, 4]), 4.5)
# median_low
self.assertEqual(whisper.aggregate('median_low', [9, 2, 5, 4]), 4)
# median_high
self.assertEqual(whisper.aggregate('median_high', [9, 2, 5, 4]), 5)

with AssertRaisesException(
whisper.InvalidAggregationMethod(
Expand Down
16 changes: 15 additions & 1 deletion whisper.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,10 @@ def _py_fallocate(fd, offset, len_):
5: 'min',
6: 'avg_zero',
7: 'absmax',
8: 'absmin'
8: 'absmin',
9: 'median',
10: 'median_low',
11: 'median_high'
})
aggregationMethodToType = dict([[v, k] for k, v in aggregationTypeToMethod.items()])
aggregationMethods = aggregationTypeToMethod.values()
Expand Down Expand Up @@ -570,6 +573,17 @@ def aggregate(aggregationMethod, knownValues, neighborValues=None):
return max(knownValues, key=abs)
elif aggregationMethod == 'absmin':
return min(knownValues, key=abs)
elif aggregationMethod == 'median':
values = sorted(knownValues)
mid, isodd = divmod(len(values), 2)
return values[mid] if isodd else float(values[mid-1] + values[mid]) / 2.0
elif aggregationMethod == 'median_low':
values = sorted(knownValues)
mid, isodd = divmod(len(values), 2)
return values[mid] if isodd else values[mid-1]
elif aggregationMethod == 'median_high':
values = sorted(knownValues)
return values[len(values) // 2]
else:
raise InvalidAggregationMethod(
"Unrecognized aggregation method %s" % aggregationMethod)
Expand Down