Skip to content

Commit

Permalink
Sum, Avg, Min and Max bucket pipeline aggregation (#10070)
Browse files Browse the repository at this point in the history
* allow parent aggs to have sub aggs defined

* adding bucket_sum aggregation

* adding bucket_avg, bucket_min and bucket_max

* fixing based on UI review

* adding tests

* disable terms sorting on pipeline aggs

* fixing based on Staceys review

* adding defaults

* updated based on review

* fixing error with stacking
  • Loading branch information
ppisljar authored Mar 1, 2017
1 parent e326567 commit 841a3d2
Show file tree
Hide file tree
Showing 20 changed files with 351 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
ng-model="agg.type"
required
auto-select-if-only-one="aggTypeOptions | aggFilter:agg.schema.aggFilter"
ng-options="agg as agg.title for agg in aggTypeOptions | aggFilter:agg.schema.aggFilter">
ng-options="agg as agg.title group by agg.subtype for agg in aggTypeOptions | aggFilter:agg.schema.aggFilter">
</select>
</div>
110 changes: 110 additions & 0 deletions src/ui/public/agg_types/__tests__/metrics/sibling_pipeline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import _ from 'lodash';
import expect from 'expect.js';
import ngMock from 'ng_mock';
import BucketSum from 'ui/agg_types/metrics/bucket_sum';
import BucketAvg from 'ui/agg_types/metrics/bucket_avg';
import BucketMin from 'ui/agg_types/metrics/bucket_min';
import BucketMax from 'ui/agg_types/metrics/bucket_max';
import VisProvider from 'ui/vis';
import StubbedIndexPattern from 'fixtures/stubbed_logstash_index_pattern';

const metrics = [
{ name: 'sum_bucket', title: 'Overall Sum', provider: BucketSum },
{ name: 'avg_bucket', title: 'Overall Average', provider: BucketAvg },
{ name: 'min_bucket', title: 'Overall Min', provider: BucketMin },
{ name: 'max_bucket', title: 'Overall Max', provider: BucketMax },
];

describe('sibling pipeline aggs', function () {
metrics.forEach(metric => {
describe(`${metric.title} metric`, function () {

let aggDsl;
let metricAgg;
let aggConfig;

function init(settings) {
ngMock.module('kibana');
ngMock.inject(function (Private) {
const Vis = Private(VisProvider);
const indexPattern = Private(StubbedIndexPattern);
metricAgg = Private(metric.provider);

const params = settings || {
customMetric: {
id: '5',
type: 'count',
schema: 'metric'
},
customBucket: {
id: '6',
type: 'date_histogram',
schema: 'bucket',
params: { field: '@timestamp' }
}
};

const vis = new Vis(indexPattern, {
title: 'New Visualization',
type: 'metric',
params: {
fontSize: 60,
handleNoResults: true
},
aggs: [
{
id: '1',
type: 'count',
schema: 'metric'
},
{
id: '2',
type: metric.name,
schema: 'metric',
params
}
],
listeners: {}
});

// Grab the aggConfig off the vis (we don't actually use the vis for anything else)
aggConfig = vis.aggs[1];
aggDsl = aggConfig.toDsl();
});
}

it(`should return a label prefixed with ${metric.title} of`, function () {
init();
expect(metricAgg.makeLabel(aggConfig)).to.eql(`${metric.title} of Count`);
});

it('should set parent aggs', function () {
init();
expect(aggDsl[metric.name].buckets_path).to.be('2-bucket>_count');
expect(aggDsl.parentAggs['2-bucket'].date_histogram).to.not.be.undefined;
});

it('should set nested parent aggs', function () {
init({
customMetric: {
id: '5',
type: 'avg',
schema: 'metric',
params: { field: 'bytes' },
},
customBucket: {
id: '6',
type: 'date_histogram',
schema: 'bucket',
params: { field: '@timestamp' },
}
});
expect(aggDsl[metric.name].buckets_path).to.be('2-bucket>2-metric');
expect(aggDsl.parentAggs['2-bucket'].date_histogram).to.not.be.undefined;
expect(aggDsl.parentAggs['2-bucket'].aggs['2-metric'].avg.field).to.equal('bytes');
});

});
});

});
4 changes: 3 additions & 1 deletion src/ui/public/agg_types/buckets/terms.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ export default function TermsAggDefinition(Private) {

const aggFilter = [
'!top_hits', '!percentiles', '!median', '!std_dev',
'!derivative', '!cumulative_sum', '!moving_avg', '!serial_diff'
'!derivative', '!moving_avg', '!serial_diff', '!cumulative_sum',
'!avg_bucket', '!max_bucket', '!min_bucket', '!sum_bucket'
];

const orderAggSchema = (new Schemas([
{
group: 'none',
Expand Down
14 changes: 14 additions & 0 deletions src/ui/public/agg_types/controls/sub_metric.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div ng-controller="aggParam.controller">
<div class="form-group" ng-if="agg.params[aggType]">
<label>{{aggTitle}}</label>
<div class="vis-editor-agg-order-agg">
<ng-form name="{{aggType}}Form">
<vis-editor-agg-params
agg="agg.params[aggType]"
group-name="'{{aggGroup}}'">
</vis-editor-agg-params>
</ng-form>
</div>
</div>

</div>
10 changes: 9 additions & 1 deletion src/ui/public/agg_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import AggTypesBucketsTermsProvider from 'ui/agg_types/buckets/terms';
import AggTypesBucketsFiltersProvider from 'ui/agg_types/buckets/filters';
import AggTypesBucketsSignificantTermsProvider from 'ui/agg_types/buckets/significant_terms';
import AggTypesBucketsGeoHashProvider from 'ui/agg_types/buckets/geo_hash';
import AggTypesMetricsBucketSumProvider from 'ui/agg_types/metrics/bucket_sum';
import AggTypesMetricsBucketAvgProvider from 'ui/agg_types/metrics/bucket_avg';
import AggTypesMetricsBucketMinProvider from 'ui/agg_types/metrics/bucket_min';
import AggTypesMetricsBucketMaxProvider from 'ui/agg_types/metrics/bucket_max';
export default function AggTypeService(Private) {

const aggs = {
Expand All @@ -42,7 +46,11 @@ export default function AggTypeService(Private) {
Private(AggTypesMetricsDerivativeProvider),
Private(AggTypesMetricsCumulativeSumProvider),
Private(AggTypesMetricsMovingAvgProvider),
Private(AggTypesMetricsSerialDiffProvider)
Private(AggTypesMetricsSerialDiffProvider),
Private(AggTypesMetricsBucketAvgProvider),
Private(AggTypesMetricsBucketSumProvider),
Private(AggTypesMetricsBucketMinProvider),
Private(AggTypesMetricsBucketMaxProvider),
],
buckets: [
Private(AggTypesBucketsDateHistogramProvider),
Expand Down
18 changes: 18 additions & 0 deletions src/ui/public/agg_types/metrics/bucket_avg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import SiblingPipelineAggHelperProvider from './lib/sibling_pipeline_agg_helper';

export default function AggTypesMetricsBucketAvgProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const siblingPipelineHelper = Private(SiblingPipelineAggHelperProvider);

return new MetricAggType({
name: 'avg_bucket',
title: 'Average Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall average'),
subtype: siblingPipelineHelper.subtype,
params: [
...siblingPipelineHelper.params()
]
});
}
18 changes: 18 additions & 0 deletions src/ui/public/agg_types/metrics/bucket_max.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import SiblingPipelineAggHelperProvider from './lib/sibling_pipeline_agg_helper';

export default function AggTypesMetricsBucketMaxProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const siblingPipelineHelper = Private(SiblingPipelineAggHelperProvider);

return new MetricAggType({
name: 'max_bucket',
title: 'Max Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall max'),
subtype: siblingPipelineHelper.subtype,
params: [
...siblingPipelineHelper.params()
]
});
}
18 changes: 18 additions & 0 deletions src/ui/public/agg_types/metrics/bucket_min.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import SiblingPipelineAggHelperProvider from './lib/sibling_pipeline_agg_helper';

export default function AggTypesMetricsBucketMinProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const siblingPipelineHelper = Private(SiblingPipelineAggHelperProvider);

return new MetricAggType({
name: 'min_bucket',
title: 'Min Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall min'),
subtype: siblingPipelineHelper.subtype,
params: [
...siblingPipelineHelper.params()
]
});
}
18 changes: 18 additions & 0 deletions src/ui/public/agg_types/metrics/bucket_sum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import AggTypesMetricsMetricAggTypeProvider from 'ui/agg_types/metrics/metric_agg_type';
import { makeNestedLabel } from './lib/make_nested_label';
import SiblingPipelineAggHelperProvider from './lib/sibling_pipeline_agg_helper';

export default function AggTypesMetricsBucketSumProvider(Private) {
const MetricAggType = Private(AggTypesMetricsMetricAggTypeProvider);
const siblingPipelineHelper = Private(SiblingPipelineAggHelperProvider);

return new MetricAggType({
name: 'sum_bucket',
title: 'Sum Bucket',
makeLabel: agg => makeNestedLabel(agg, 'overall sum'),
subtype: siblingPipelineHelper.subtype,
params: [
...siblingPipelineHelper.params()
]
});
}
1 change: 1 addition & 0 deletions src/ui/public/agg_types/metrics/cumulative_sum.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default function AggTypeMetricComulativeSumProvider(Private) {
return new MetricAggType({
name: 'cumulative_sum',
title: 'Cumulative Sum',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'cumulative sum'),
params: [
...parentPipelineAggHelper.params()
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/agg_types/metrics/derivative.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default function AggTypeMetricDerivativeProvider(Private) {
return new MetricAggType({
name: 'derivative',
title: 'Derivative',
subtype: parentPipelineAggHelper.subtype,
makeLabel: agg => makeNestedLabel(agg, 'derivative'),
params: [
...parentPipelineAggHelper.params()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const ParentPipelineAggHelperProvider = function (Private) {
])).all[0];

return {
subtype: 'Parent Pipeline Aggregations',
params: function () {
return [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import safeMakeLabel from './safe_make_label';

const siblingPipelineAggController = function (type) {
return function ($scope) {

$scope.aggType = type;
$scope.aggTitle = type === 'customMetric' ? 'Metric' : 'Bucket';
$scope.aggGroup = type === 'customMetric' ? 'metrics' : 'buckets';
$scope.safeMakeLabel = safeMakeLabel;

function updateAgg() {
const agg = $scope.agg;
const params = agg.params;
const paramDef = agg.type.params.byName[type];

params[type] = params[type] || paramDef.makeAgg(agg);
}

updateAgg();
};
};

export { siblingPipelineAggController };
92 changes: 92 additions & 0 deletions src/ui/public/agg_types/metrics/lib/sibling_pipeline_agg_helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import _ from 'lodash';
import VisAggConfigProvider from 'ui/vis/agg_config';
import VisSchemasProvider from 'ui/vis/schemas';

import { siblingPipelineAggController } from './sibling_pipeline_agg_controller';
import { siblingPipelineAggWritter } from './sibling_pipeline_agg_writter';
import metricAggTemplate from 'ui/agg_types/controls/sub_metric.html';

const SiblingPipelineAggHelperProvider = function (Private) {

const AggConfig = Private(VisAggConfigProvider);
const Schemas = Private(VisSchemasProvider);

const metricAggFilter = [
'!top_hits', '!percentiles', '!percentile_ranks', '!median', '!std_dev',
'!sum_bucket', '!avg_bucket', '!min_bucket', '!max_bucket',
'!derivative', '!moving_avg', '!serial_diff', '!cumulative_sum'
];

const metricAggSchema = (new Schemas([
{
group: 'none',
name: 'metricAgg',
title: 'Metric Agg',
aggFilter: metricAggFilter
}
])).all[0];

const bucketAggFilter = [];
const bucketAggSchema = (new Schemas([
{
group: 'none',
title: 'Bucket Agg',
name: 'bucketAgg',
aggFilter: bucketAggFilter
}
])).all[0];

return {
subtype: 'Sibling Pipeline Aggregations',
params: function () {
return [
{
name: 'customBucket',
type: AggConfig,
default: null,
serialize: function (customMetric) {
return customMetric.toJSON();
},
deserialize: function (state, agg) {
return this.makeAgg(agg, state);
},
makeAgg: function (agg, state) {
state = state || { type: 'date_histogram' };
state.schema = bucketAggSchema;
const orderAgg = new AggConfig(agg.vis, state);
orderAgg.id = agg.id + '-bucket';
return orderAgg;
},
editor: metricAggTemplate,
controller: siblingPipelineAggController('customBucket'),
write: _.noop
},
{
name: 'customMetric',
type: AggConfig,
default: null,
serialize: function (customMetric) {
return customMetric.toJSON();
},
deserialize: function (state, agg) {
return this.makeAgg(agg, state);
},
makeAgg: function (agg, state) {
state = state || { type: 'count' };
state.schema = metricAggSchema;
const orderAgg = new AggConfig(agg.vis, state);
orderAgg.id = agg.id + '-metric';
return orderAgg;
},
editor: metricAggTemplate,
controller: siblingPipelineAggController('customMetric'),
write: siblingPipelineAggWritter
}
];
}
};


};

export default SiblingPipelineAggHelperProvider;
Loading

0 comments on commit 841a3d2

Please sign in to comment.