diff --git a/public/app/plugins/datasource/elasticsearch/bucketAgg.js b/public/app/plugins/datasource/elasticsearch/bucketAgg.js
index 03b58569325..6a618cceea7 100644
--- a/public/app/plugins/datasource/elasticsearch/bucketAgg.js
+++ b/public/app/plugins/datasource/elasticsearch/bucketAgg.js
@@ -33,24 +33,26 @@ function (angular, _, queryDef) {
};
$scope.validateModel = function() {
+ $scope.index = _.indexOf(bucketAggs, $scope.agg);
+
$scope.isFirst = $scope.index === 0;
$scope.isLast = $scope.index === bucketAggs.length - 1;
- $scope.aggOptionsString = "";
+ $scope.settingsLinkText = "";
if ($scope.agg.type === "terms") {
$scope.agg.order = $scope.agg.order || "desc";
$scope.agg.size = $scope.agg.size || "0";
- $scope.agg.orderBy = $scope.agg.orderBy || "_count";
+ $scope.agg.orderBy = $scope.agg.orderBy || "_term";
if ($scope.agg.size === '0') {
- $scope.aggOptionsString = "";
+ $scope.settingsLinkText = "";
} else {
- $scope.aggOptionsString = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', '
+ $scope.settingsLinkText = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', '
}
- $scope.aggOptionsString += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
+ $scope.settingsLinkText += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
if ($scope.agg.size === '0') {
- $scope.aggOptionsString += ' (' + $scope.agg.order + ')';
+ $scope.settingsLinkText += ' (' + $scope.agg.order + ')';
}
}
diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js
index 7622fa243c0..38b28b7fc02 100644
--- a/public/app/plugins/datasource/elasticsearch/datasource.js
+++ b/public/app/plugins/datasource/elasticsearch/datasource.js
@@ -175,10 +175,18 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
// This is quite complex
// neeed to recurise down the nested buckets to build series
ElasticDatasource.prototype._processBuckets = function(aggs, target, series, level, parentName) {
- var seriesName, value, metric, i, y, bucket, childBucket, aggDef, esAgg;
+ var seriesName, value, metric, i, y, z, bucket, childBucket, aggDef, esAgg;
var buckets;
var dataFound = 0;
+ function addMetricPoint(seriesName, value, time) {
+ var current = series[seriesName];
+ if (!current) {
+ current = series[seriesName] = {target: seriesName, datapoints: []};
+ }
+ current.datapoints.push([value, time]);
+ }
+
aggDef = target.bucketAggs[level];
esAgg = aggs[aggDef.id];
@@ -191,16 +199,27 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
metric = target.metrics[y];
seriesName = parentName;
- if (metric.type === 'count') {
- seriesName += ' count';
- value = bucket.doc_count;
- } else {
- seriesName += ' ' + metric.field + ' ' + metric.type;
- value = bucket[metric.id].value;
+ switch(metric.type) {
+ case 'count': {
+ seriesName += ' count';
+ value = bucket.doc_count;
+ addMetricPoint(seriesName, value, bucket.key);
+ break;
+ }
+ case 'percentiles': {
+ var values = bucket[metric.id].values;
+ for (var prop in values) {
+ addMetricPoint(seriesName + ' ' + prop, values[prop], bucket.key)
+ }
+ break;
+ }
+ default: {
+ seriesName += ' ' + metric.field + ' ' + metric.type;
+ value = bucket[metric.id].value;
+ addMetricPoint(seriesName, value, bucket.key);
+ break;
+ }
}
-
- var serie = series[seriesName] = series[seriesName] || {target: seriesName, datapoints: []};
- serie.datapoints.push([value, bucket.key]);
}
}
else {
diff --git a/public/app/plugins/datasource/elasticsearch/metricAgg.js b/public/app/plugins/datasource/elasticsearch/metricAgg.js
index f6670879741..fa5fa837c93 100644
--- a/public/app/plugins/datasource/elasticsearch/metricAgg.js
+++ b/public/app/plugins/datasource/elasticsearch/metricAgg.js
@@ -8,27 +8,43 @@ function (angular, _, queryDef) {
var module = angular.module('grafana.directives');
- module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q) {
+ module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q, $rootScope) {
var metricAggs = $scope.target.metrics;
$scope.metricAggTypes = queryDef.metricAggTypes;
$scope.init = function() {
$scope.agg = metricAggs[$scope.index];
+ $scope.validateModel();
+ }
+
+ $rootScope.onAppEvent('elastic-query-updated', function() {
+ $scope.index = _.indexOf(metricAggs, $scope.agg);
+
+ $scope.isFirst = $scope.index === 0;
+ $scope.isSingle = metricAggs.length === 1;
+ $scope.validateModel();
+ });
+
+ $scope.validateModel = function() {
if (!$scope.agg.field) {
$scope.agg.field = 'select field';
}
- }
- $scope.$watchCollection("target.metrics", function() {
- $scope.isFirst = $scope.index === 0;
- $scope.isLast = $scope.index === metricAggs.length - 1;
- $scope.isSingle = metricAggs.length === 1;
- });
+ if ($scope.agg.type === 'percentiles') {
+ $scope.agg.settings.percents = $scope.agg.settings.percents || [25,50,75,95,99];
+ $scope.settingsLinkText = 'values: ' + $scope.agg.settings.percents.join(',');
+ }
+ }
$scope.toggleOptions = function() {
$scope.showOptions = !$scope.showOptions;
- }
+ };
+
+ $scope.onTypeChange = function() {
+ $scope.agg.settings = {};
+ $scope.onChange();
+ };
$scope.addMetricAgg = function() {
var addIndex = metricAggs.length;
diff --git a/public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html b/public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html
index e89230f0c97..6186ebba114 100644
--- a/public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html
+++ b/public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html
@@ -8,8 +8,8 @@
-
- {{aggOptionsString}}
+
+ {{settingsLinkText}}
diff --git a/public/app/plugins/datasource/elasticsearch/partials/metricAgg.html b/public/app/plugins/datasource/elasticsearch/partials/metricAgg.html
index 109e7c63cec..6fcb49d49b0 100644
--- a/public/app/plugins/datasource/elasticsearch/partials/metricAgg.html
+++ b/public/app/plugins/datasource/elasticsearch/partials/metricAgg.html
@@ -4,13 +4,13 @@
Metric
-
+
-
- {{aggOptionsString}}
+
+ {{settingsLinkText}}
@@ -25,4 +25,18 @@
-
+
diff --git a/public/app/plugins/datasource/elasticsearch/queryBuilder.js b/public/app/plugins/datasource/elasticsearch/queryBuilder.js
index 2eef154e83b..0090e5613f8 100644
--- a/public/app/plugins/datasource/elasticsearch/queryBuilder.js
+++ b/public/app/plugins/datasource/elasticsearch/queryBuilder.js
@@ -48,7 +48,7 @@ function (angular) {
esAgg["date_histogram"] = {
"interval": target.interval || "$interval",
"field": aggDef.field,
- "min_doc_count": 0,
+ "min_doc_count": 1,
"extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }
};
break;
@@ -92,8 +92,15 @@ function (angular) {
continue;
}
+ var metricAgg = {field: metric.field};
+ for (var prop in metric.settings) {
+ if (metric.settings.hasOwnProperty(prop)) {
+ metricAgg[prop] = metric.settings[prop];
+ }
+ }
+
var aggField = {};
- aggField[metric.type] = {field: metric.field};
+ aggField[metric.type] = metricAgg;
nestedAggs.aggs[metric.id] = aggField;
}
diff --git a/public/app/plugins/datasource/elasticsearch/queryDef.js b/public/app/plugins/datasource/elasticsearch/queryDef.js
index 46172eb0ad7..57b3a3e2e24 100644
--- a/public/app/plugins/datasource/elasticsearch/queryDef.js
+++ b/public/app/plugins/datasource/elasticsearch/queryDef.js
@@ -12,6 +12,7 @@ function (_) {
{text: "Max of", value: 'max' },
{text: "Min of", value: 'min' },
{text: "Standard Deviations", value: 'std_dev' },
+ {text: "Percentiles", value: 'percentiles' },
],
bucketAggTypes: [
diff --git a/public/test/specs/elasticsearch-querybuilder-specs.js b/public/test/specs/elasticsearch-querybuilder-specs.js
index 6622a2462a6..b28f5eea41f 100644
--- a/public/test/specs/elasticsearch-querybuilder-specs.js
+++ b/public/test/specs/elasticsearch-querybuilder-specs.js
@@ -65,6 +65,31 @@ define([
expect(secondLevel.aggs["5"].avg.field).to.be("@value");
});
+ it('with metric percentiles', function() {
+ var builder = new ElasticQueryBuilder();
+
+ var query = builder.build({
+ metrics: [
+ {
+ id: '1',
+ type: 'percentiles',
+ field: '@load_time',
+ settings: {
+ percents: [1,2,3,4]
+ }
+ }
+ ],
+ bucketAggs: [
+ {type: 'date_histogram', field: '@timestamp', id: '3'}
+ ],
+ }, 100, 1000);
+
+ var firstLevel = query.aggs["3"];
+
+ expect(firstLevel.aggs["1"].percentiles.field).to.be("@load_time");
+ expect(firstLevel.aggs["1"].percentiles.percents).to.eql([1,2,3,4]);
+ });
+
});
});
diff --git a/public/test/specs/elasticsearch-specs.js b/public/test/specs/elasticsearch-specs.js
index f4de2cf3e8c..5c3c9049721 100644
--- a/public/test/specs/elasticsearch-specs.js
+++ b/public/test/specs/elasticsearch-specs.js
@@ -145,6 +145,48 @@ define([
});
});
+ describe('with percentiles ', function() {
+ var result;
+
+ beforeEach(function() {
+ result = ctx.ds._processTimeSeries([{
+ refId: 'A',
+ metrics: [{type: 'percentiles', settings: {percents: [75, 90]}, id: '1'}],
+ bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '3'}],
+ }], {
+ responses: [{
+ aggregations: {
+ "3": {
+ buckets: [
+ {
+ "1": {values: {"75": 3.3, "90": 5.5}},
+ doc_count: 10,
+ key: 1000
+ },
+ {
+ "1": {values: {"75": 2.3, "90": 4.5}},
+ doc_count: 15,
+ key: 2000
+ }
+ ]
+ }
+ }
+ }]
+ });
+ });
+
+ it('should return 2 series', function() {
+ expect(result.data.length).to.be(2);
+ expect(result.data[0].datapoints.length).to.be(2);
+ expect(result.data[0].target).to.be('A 75');
+ expect(result.data[1].target).to.be('A 90');
+ expect(result.data[0].datapoints[0][0]).to.be(3.3);
+ expect(result.data[0].datapoints[0][1]).to.be(1000);
+ expect(result.data[1].datapoints[1][0]).to.be(4.5);
+ });
+ });
+
+
});
});
});