From 085c4c56b87369797940be087fed9930c885e1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Mar 2017 13:44:01 +0200 Subject: [PATCH] elasticearch: added support for histogram aggregations, closes #3164 --- CHANGELOG.md | 1 + .../datasource/elasticsearch/bucket_agg.js | 11 +++++++ .../elasticsearch/partials/bucket_agg.html | 11 +++++++ .../datasource/elasticsearch/query_builder.js | 17 ++++++++++ .../datasource/elasticsearch/query_def.js | 1 + .../specs/elastic_response_specs.ts | 33 +++++++++++++++++++ .../specs/query_builder_specs.ts | 17 ++++++++++ 7 files changed, 91 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5470a86fb47..82b3ba2037e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * **InfluxDB**: Small fix for the "glow" when focus the field for LIMIT and SLIMIT [#7799](https://github.com/grafana/grafana/pull/7799) thx [@thuck](https://github.com/thuck) * **Panels**: Delay loading & Lazy load panels as they become visible (scrolled into view) [#5216](https://github.com/grafana/grafana/issues/5216) thx [@jifwin](https://github.com/jifwin) * **Graph**: Support auto grid min/max when using log scale [#3090](https://github.com/grafana/grafana/issues/3090), thx [@bigbenhur](https://github.com/bigbenhur) +* **Elasticsearch**: Support histogram aggregations [#3164](https://github.com/grafana/grafana/issues/3164) ## Minor Enchancements diff --git a/public/app/plugins/datasource/elasticsearch/bucket_agg.js b/public/app/plugins/datasource/elasticsearch/bucket_agg.js index 28f1df08251..d6d641c1655 100644 --- a/public/app/plugins/datasource/elasticsearch/bucket_agg.js +++ b/public/app/plugins/datasource/elasticsearch/bucket_agg.js @@ -50,6 +50,7 @@ function (angular, _, queryDef) { switch($scope.agg.type) { case 'date_histogram': + case 'histogram': case 'terms': { delete $scope.agg.query; $scope.agg.field = 'select field'; @@ -132,6 +133,16 @@ function (angular, _, queryDef) { } break; } + case 'histogram': { + settings.interval = settings.interval || 1000; + settings.min_doc_count = _.defaultTo(settings.min_doc_count, 1); + settingsLinkText = 'Interval: ' + settings.interval; + + if (settings.min_doc_count > 0) { + settingsLinkText += ', Min Doc Count: ' + settings.min_doc_count; + } + break; + } case 'geohash_grid': { // limit precision to 7 settings.precision = Math.max(Math.min(settings.precision, 7), 1); diff --git a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html index 562f0b86e56..f1e650f6830 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html +++ b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html @@ -52,6 +52,17 @@ +
+
+ + +
+
+ + +
+
+
diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index 11e8b69ddaa..808fea3cc70 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -79,6 +79,19 @@ function (queryDef) { return esAgg; }; + ElasticQueryBuilder.prototype.getHistogramAgg = function(aggDef) { + var esAgg = {}; + var settings = aggDef.settings || {}; + esAgg.interval = settings.interval; + esAgg.field = aggDef.field; + esAgg.min_doc_count = settings.min_doc_count || 0; + + if (settings.missing) { + esAgg.missing = settings.missing; + } + return esAgg; + }; + ElasticQueryBuilder.prototype.getFiltersAgg = function(aggDef) { var filterObj = {}; for (var i = 0; i < aggDef.settings.filters.length; i++) { @@ -192,6 +205,10 @@ function (queryDef) { esAgg["date_histogram"] = this.getDateHistogramAgg(aggDef); break; } + case 'histogram': { + esAgg["histogram"] = this.getHistogramAgg(aggDef); + break; + } case 'filters': { esAgg["filters"] = {filters: this.getFiltersAgg(aggDef)}; break; diff --git a/public/app/plugins/datasource/elasticsearch/query_def.js b/public/app/plugins/datasource/elasticsearch/query_def.js index 5afc908edba..a55e2dfd9e5 100644 --- a/public/app/plugins/datasource/elasticsearch/query_def.js +++ b/public/app/plugins/datasource/elasticsearch/query_def.js @@ -24,6 +24,7 @@ function (_) { {text: "Filters", value: 'filters' }, {text: "Geo Hash Grid", value: 'geohash_grid', requiresField: true}, {text: "Date Histogram", value: 'date_histogram', requiresField: true}, + {text: "Histogram", value: 'histogram', requiresField: true}, ], orderByOptions: [ diff --git a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts index 4b87cc52c04..589e0ccbfab 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts @@ -361,6 +361,39 @@ describe('ElasticResponse', function() { }); }); + describe('histogram response', function() { + var result; + + beforeEach(function() { + targets = [{ + refId: 'A', + metrics: [{type: 'count', id: '1'}], + bucketAggs: [{type: 'histogram', field: 'bytes', id: '3'}], + }]; + response = { + responses: [{ + aggregations: { + "3": { + buckets: [ + {doc_count: 1, key: 1000}, + {doc_count: 3, key: 2000}, + {doc_count: 2, key: 1000}, + ] + } + } + }] + }; + + result = new ElasticResponse(targets, response).getTimeSeries(); + }); + + it('should return docs with byte and count', function() { + expect(result.data[0].datapoints.length).to.be(3); + expect(result.data[0].datapoints[0].Count).to.be(1); + expect(result.data[0].datapoints[0].bytes).to.be(1000); + }); + }); + describe('with two filters agg', function() { var result; diff --git a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts index e60cde7a163..18645ad498d 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts @@ -249,6 +249,23 @@ describe('ElasticQueryBuilder', function() { expect(firstLevel.aggs["2"].derivative.buckets_path).to.be("3"); }); + it('with histogram', function() { + var query = builder.build({ + metrics: [ + {id: '1', type: 'count' }, + ], + bucketAggs: [ + {type: 'histogram', field: 'bytes', id: '3', settings: {interval: 10, min_doc_count: 2, missing: 5}} + ], + }); + + var firstLevel = query.aggs["3"]; + expect(firstLevel.histogram.field).to.be('bytes'); + expect(firstLevel.histogram.interval).to.be(10); + expect(firstLevel.histogram.min_doc_count).to.be(2); + expect(firstLevel.histogram.missing).to.be(5); + }); + it('with adhoc filters', function() { var query = builder.build({ metrics: [{type: 'Count', id: '0'}],