Parcourir la source

elasticearch: added support for histogram aggregations, closes #3164

Torkel Ödegaard il y a 8 ans
Parent
commit
085c4c56b8

+ 1 - 0
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
 

+ 11 - 0
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);

+ 11 - 0
public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html

@@ -52,6 +52,17 @@
 		</div>
 	</div>
 
+	<div ng-if="agg.type === 'histogram'">
+		<div class="gf-form offset-width-7">
+			<label class="gf-form-label width-10">Interval</label>
+			<input type="number" class="gf-form-input max-width-12" ng-model="agg.settings.interval" ng-blur="onChangeInternal()">
+		</div>
+		<div class="gf-form offset-width-7">
+			<label class="gf-form-label width-10">Min Doc Count</label>
+			<input type="number" class="gf-form-input max-width-12" ng-model="agg.settings.min_doc_count" ng-blur="onChangeInternal()">
+		</div>
+	</div>
+
 	<div ng-if="agg.type === 'terms'">
 		<div class="gf-form offset-width-7">
 			<label class="gf-form-label width-10">Order</label>

+ 17 - 0
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;

+ 1 - 0
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: [

+ 33 - 0
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;
 

+ 17 - 0
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'}],