Procházet zdrojové kódy

feat(elasticsearch): lots of work on elasticsearch metrics query editor, #1034

Torkel Ödegaard před 10 roky
rodič
revize
590b155c6c

+ 26 - 14
public/app/plugins/datasource/elasticsearch/datasource.js

@@ -174,29 +174,41 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
 
     // This is quite complex
     // neeed to recurise down the nested buckets to build series
-    ElasticDatasource.prototype._processBuckets = function(buckets, groupByFields, series, level, parentName, parentTime) {
+    ElasticDatasource.prototype._processBuckets = function(buckets, target, series, level, parentName, parentTime) {
       var points = [];
-      var groupBy = groupByFields[level];
+      var groupBy = target.groupByFields[level];
 
       for (var i = 0; i < buckets.length; i++) {
         var bucket = buckets[i];
 
         if (groupBy) {
-          var seriesName = level > 0 ? bucket.key : '';
+          var seriesName = level > 0 ? parentName + ' ' + bucket.key : parentName;
           var time = parentTime || bucket.key;
-          this._processBuckets(bucket[groupBy.field].buckets, groupByFields, series, level+1, seriesName, time)
+          this._processBuckets(bucket[groupBy.field].buckets, target, series, level+1, seriesName, time)
         } else {
-          var seriesName = parentName;
 
-          if (level > 0) {
-            if (seriesName) { seriesName += " "; }
-            seriesName += bucket.key;
-          } else {
-            parentTime = bucket.key;
-          }
+          for (var y = 0; y < target.select.length; y++) {
+            var select = target.select[y];
+            var seriesName = parentName;
+            var value;
+
+            if (level > 0) {
+              seriesName +=  ' ' + bucket.key;
+            } else {
+              parentTime = bucket.key;
+            }
 
-          var serie = series[seriesName] = series[seriesName] || {target: seriesName, datapoints: []};
-          serie.datapoints.push([bucket.doc_count, parentTime]);
+            if (select.field) {
+              seriesName += ' ' + select.field;
+              value = bucket[select.field].value;
+            } else {
+              seriesName += ' count';
+              value = bucket.doc_count;
+            }
+
+            var serie = series[seriesName] = series[seriesName] || {target: seriesName, datapoints: []};
+            serie.datapoints.push([value, parentTime]);
+          }
         }
       }
     };
@@ -215,7 +227,7 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
         var points = [];
         var querySeries = {}
 
-        this._processBuckets(buckets, target.groupByFields, querySeries, 0);
+        this._processBuckets(buckets, target, querySeries, 0, target.refId);
 
         _.each(querySeries, function(value) {
           series.push(value);

+ 30 - 9
public/app/plugins/datasource/elasticsearch/queryCtrl.js

@@ -22,7 +22,7 @@ function (angular, _, ElasticQueryBuilder) {
       var target = $scope.target;
       target.function = target.function || 'mean';
       target.timeField = target.timeField || '@timestamp';
-      target.select = target.select || [{ agg: 'Count' }];
+      target.select = target.select || [{ agg: 'count' }];
       target.groupByFields = target.groupByFields || [];
 
       $scope.timeSegment = uiSegmentSrv.newSegment(target.timeField);
@@ -31,8 +31,16 @@ function (angular, _, ElasticQueryBuilder) {
         return uiSegmentSrv.newSegment(group.field);
       });
 
+      $scope.initSelectSegments();
+      $scope.groupBySegments.push(uiSegmentSrv.newPlusButton());
+      $scope.removeSelectSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove select --'});
+      $scope.resetSelectSegment = uiSegmentSrv.newSegment({fake: true, value: '-- reset --'});
+      $scope.removeGroupBySegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove group by --'});
+    };
+
+    $scope.initSelectSegments = function() {
       $scope.selectSegments = [];
-      _.each(target.select, function(select) {
+      _.each($scope.target.select, function(select) {
         if ($scope.selectSegments.length > 0) {
           $scope.selectSegments.push(uiSegmentSrv.newCondition(" and "));
         }
@@ -44,10 +52,7 @@ function (angular, _, ElasticQueryBuilder) {
         }
       });
 
-      $scope.groupBySegments.push(uiSegmentSrv.newPlusButton());
       $scope.selectSegments.push(uiSegmentSrv.newPlusButton());
-      $scope.removeSelectSegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove select --'});
-      $scope.removeGroupBySegment = uiSegmentSrv.newSegment({fake: true, value: '-- remove group by --'});
     };
 
     $scope.getSelectSegments = function(segment, index) {
@@ -55,12 +60,15 @@ function (angular, _, ElasticQueryBuilder) {
         var options = [
           uiSegmentSrv.newSegment({value: 'count', type: 'agg'}),
           uiSegmentSrv.newSegment({value: 'min',   type: 'agg', reqField: true}),
-          uiSegmentSrv.newSegment({value: 'count', type: 'agg', reqField: true}),
+          uiSegmentSrv.newSegment({value: 'max',   type: 'agg', reqField: true}),
           uiSegmentSrv.newSegment({value: 'avg',   type: 'agg', reqField: true}),
         ];
-        if (index > 0) {
+        if (segment.type !== 'plus-button' && $scope.selectSegments.length > 3) {
           options.splice(0, 0, angular.copy($scope.removeSelectSegment));
         }
+        if (index === 0 && $scope.selectSegments.length > 2) {
+          options.splice(0, 0, angular.copy($scope.resetSelectSegment));
+        }
         return $q.when(options);
       }
 
@@ -70,17 +78,28 @@ function (angular, _, ElasticQueryBuilder) {
     };
 
     $scope.selectChanged = function(segment, index) {
+      // reset
+      if (segment.value === $scope.resetSelectSegment.value) {
+        $scope.target.select = [{ agg: 'count' }];
+        $scope.initSelectSegments();
+        $scope.get_data();
+        return;
+      }
+
+      // remove this select field
       if (segment.value === $scope.removeSelectSegment.value) {
         var nextSegment = $scope.selectSegments[index + 1];
         var remove = 2;
         if (nextSegment && nextSegment.type === 'field') {
           remove += 1;
         }
-        $scope.selectSegments.splice(index-1, remove);
+        $scope.selectSegments.splice(Math.max(index-1, 0), remove);
         $scope.rebuildTargetSelects();
+        $scope.get_data();
         return;
       }
 
+      // add new
       if (segment.type === 'plus-button' && index > 0) {
         $scope.selectSegments.splice(index, 0, uiSegmentSrv.newCondition(' And '));
         segment.type = 'agg';
@@ -102,6 +121,7 @@ function (angular, _, ElasticQueryBuilder) {
       }
 
       $scope.rebuildTargetSelects();
+      $scope.get_data();
     };
 
     $scope.rebuildTargetSelects = function() {
@@ -110,13 +130,14 @@ function (angular, _, ElasticQueryBuilder) {
         var segment = $scope.selectSegments[i];
         var select = {agg: segment.value };
 
-        if (segment.type === 'agg' && segment.reqField) {
+        if (segment.type === 'agg' && segment.value !== 'count') {
           select.field = $scope.selectSegments[i+1].value;
           i += 2;
         } else {
           i += 1;
         }
 
+        if (select.field === 'select field') { continue; }
         $scope.target.select.push(select);
       };
     };

+ 1 - 1
public/test/specs/elasticsearch-querybuilder-specs.js

@@ -25,7 +25,7 @@ define([
         groupByFields: [],
       }, 100, 1000);
 
-      expect(query.query.filtered.filter.bool.must[0].range["@timestamp"].gte).to.be(100);
+      var aggs = query.aggs.histogram;
     });
 
 

+ 61 - 9
public/test/specs/elasticsearch-specs.js

@@ -17,12 +17,13 @@ define([
 
     describe('When processing es response', function() {
 
-      describe('simple query', function() {
+      describe('simple query and count', function() {
         var result;
 
         beforeEach(function() {
           result = ctx.ds._processTimeSeries([{
             refId: 'A',
+            select: [{agg: 'count'}],
             groupByFields: [],
           }], {
             responses: [{
@@ -53,11 +54,58 @@ define([
 
       });
 
+      describe('simple query count & avg aggregation', function() {
+        var result;
+
+        beforeEach(function() {
+          result = ctx.ds._processTimeSeries([{
+            refId: 'A',
+            select: [{agg: 'count'}, {agg: 'avg', field: 'value'}],
+            groupByFields: [],
+          }], {
+            responses: [{
+              aggregations: {
+                histogram: {
+                  buckets: [
+                    {
+                      value: {value: 88},
+                      doc_count: 10,
+                      key: 1000
+                    },
+                    {
+                      value: {value: 99},
+                      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].datapoints[0][0]).to.be(10);
+          expect(result.data[0].datapoints[0][1]).to.be(1000);
+
+          expect(result.data[1].target).to.be("A value");
+          expect(result.data[1].datapoints[0][0]).to.be(88);
+          expect(result.data[1].datapoints[1][0]).to.be(99);
+        });
+
+      });
+
       describe('single group by query', function() {
         var result;
 
         beforeEach(function() {
-          result = ctx.ds._processTimeSeries([{refId: 'A', groupByFields: [{field: 'host' }]}], {
+          result = ctx.ds._processTimeSeries([{
+            refId: 'A',
+            select: [{agg: 'count'}],
+            groupByFields: [{field: 'host' }]
+          }], {
             responses: [{
               aggregations: {
                 histogram: {
@@ -92,8 +140,8 @@ define([
         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('server1');
-          expect(result.data[1].target).to.be('server2');
+          expect(result.data[0].target).to.be('A server1 count');
+          expect(result.data[1].target).to.be('A server2 count');
         });
       });
 
@@ -101,7 +149,11 @@ define([
         var result;
 
         beforeEach(function() {
-          result = ctx.ds._processTimeSeries([{refId: 'A', groupByFields: [{field: 'host'}, {field: 'site'}]}], {
+          result = ctx.ds._processTimeSeries([{
+              refId: 'A',
+              select: [{agg: 'count'}],
+              groupByFields: [{field: 'host'}, {field: 'site'}]
+            }], {
             responses: [{
               aggregations: {
                 histogram: {
@@ -170,10 +222,10 @@ define([
         it('should return 2 series', function() {
           expect(result.data.length).to.be(4);
           expect(result.data[0].datapoints.length).to.be(2);
-          expect(result.data[0].target).to.be('server1 backend');
-          expect(result.data[1].target).to.be('server1 frontend');
-          expect(result.data[2].target).to.be('server2 backend');
-          expect(result.data[3].target).to.be('server2 frontend');
+          expect(result.data[0].target).to.be('A server1 backend count');
+          expect(result.data[1].target).to.be('A server1 frontend count');
+          expect(result.data[2].target).to.be('A server2 backend count');
+          expect(result.data[3].target).to.be('A server2 frontend count');
         });
       });