瀏覽代碼

feat(elasticsearch): worked on elasticsearch templating support, #2696

Torkel Ödegaard 10 年之前
父節點
當前提交
bc3c394210

+ 10 - 2
public/app/plugins/datasource/elasticsearch/bucketAgg.js

@@ -39,7 +39,7 @@ function (angular, _, queryDef) {
         case 'date_histogram':
         case 'terms':  {
           delete $scope.agg.query;
-          $scope.agg.type = 'select field';
+          $scope.agg.field = 'select field';
           break;
         }
         case 'filters': {
@@ -120,6 +120,14 @@ function (angular, _, queryDef) {
       $scope.orderByOptions = queryDef.getOrderByOptions($scope.target);
     };
 
+    $scope.getFieldsInternal = function() {
+      if ($scope.agg.type === 'date_histogram') {
+        return $scope.getFields({$fieldType: 'date'});
+      } else {
+        return $scope.getFields();
+      }
+    };
+
     $scope.addBucketAgg = function() {
       // if last is date histogram add it before
       var lastBucket = bucketAggs[bucketAggs.length - 1];
@@ -133,7 +141,7 @@ function (angular, _, queryDef) {
         return parseInt(val.id) > max ? parseInt(val.id) : max;
       }, 0);
 
-      bucketAggs.splice(addIndex, 0, {type: "terms", field: "select field", id: (id+1).toString()});
+      bucketAggs.splice(addIndex, 0, {type: "terms", field: "select field", id: (id+1).toString(), fake: true});
       $scope.onChange();
     };
 

+ 46 - 7
public/app/plugins/datasource/elasticsearch/datasource.js

@@ -14,7 +14,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
 
   var module = angular.module('grafana.services');
 
-  module.factory('ElasticDatasource', function($q, backendSrv, templateSrv) {
+  module.factory('ElasticDatasource', function($q, backendSrv, templateSrv, timeSrv) {
 
     function ElasticDatasource(datasource) {
       this.type = 'elasticsearch';
@@ -168,7 +168,6 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
       payload = payload.replace(/\$interval/g, options.interval);
       payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf());
       payload = payload.replace(/\$timeTo/g, options.range.to.valueOf());
-      payload = payload.replace(/\$maxDataPoints/g, options.maxDataPoints);
       payload = templateSrv.replace(payload, options.scopedVars);
 
       return this._post('/_msearch?search_type=count', payload).then(function(res) {
@@ -176,9 +175,17 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
       });
     };
 
-    ElasticDatasource.prototype.metricFindQuery = function() {
+    ElasticDatasource.prototype.getFields = function(query) {
       return this._get('/_mapping').then(function(res) {
         var fields = {};
+        var typeMap = {
+          'float': 'number',
+          'double': 'number',
+          'integer': 'number',
+          'long': 'number',
+          'date': 'date',
+          'string': 'string',
+        };
 
         for (var indexName in res) {
           var index = res[indexName];
@@ -188,21 +195,53 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
             var properties = mappings[typeName].properties;
             for (var field in properties) {
               var prop = properties[field];
+              if (query.type && typeMap[prop.type] !== query.type) {
+                continue;
+              }
               if (prop.type && field[0] !== '_') {
-                fields[field] = prop;
+                fields[field] = {text: field, type: prop.type};
               }
             }
           }
         }
 
-        fields = _.map(_.keys(fields), function(field) {
-          return {text: field};
+        // transform to array
+        return _.map(fields, function(value) {
+          return value;
         });
+      });
+    };
+
+    ElasticDatasource.prototype.getTerms = function(queryDef) {
+      var range = timeSrv.timeRange();
+      var header = this.getQueryHeader(range.from, range.to);
+      var esQuery = angular.toJson(this.queryBuilder.getTermsQuery(queryDef));
+
+      esQuery = esQuery.replace("$lucene_query", queryDef.query || '*');
+      esQuery = esQuery.replace(/\$timeFrom/g, range.from.valueOf());
+      esQuery = esQuery.replace(/\$timeTo/g, range.to.valueOf());
+      esQuery = header + '\n' + esQuery + '\n';
 
-        return fields;
+      return this._post('/_msearch?search_type=count', esQuery).then(function(res) {
+        var buckets = res.responses[0].aggregations["1"].buckets;
+        return _.map(buckets, function(bucket) {
+          return {text: bucket.key, value: bucket.key};
+        });
       });
     };
 
+    ElasticDatasource.prototype.metricFindQuery = function(query) {
+      query = templateSrv.replace(query);
+      query = angular.fromJson(query);
+
+      if (query.find === 'fields') {
+        return this.getFields(query);
+      }
+      if (query.find === 'terms') {
+        return this.getTerms(query);
+      }
+    };
+
     ElasticDatasource.prototype.getDashboard = function(id) {
       return this._get('/dashboard/' + id)
       .then(function(result) {

+ 4 - 0
public/app/plugins/datasource/elasticsearch/metricAgg.js

@@ -70,6 +70,10 @@ function (angular, _, queryDef) {
       $scope.onChange();
     };
 
+    $scope.getFieldsInternal = function() {
+      return $scope.getFields({$fieldType: 'number'});
+    };
+
     $scope.addMetricAgg = function() {
       var addIndex = metricAggs.length;
 

+ 1 - 1
public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html

@@ -8,7 +8,7 @@
 			<metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onTypeChanged()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
 		</li>
 		<li ng-if="agg.field">
-			<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
+			<metric-segment-model property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
 		</li>
 		<li ng-if="!agg.field">
 			<span class="tight-form-item tight-form-item-xxlarge">&nbsp;</span>

+ 1 - 1
public/app/plugins/datasource/elasticsearch/partials/metricAgg.html

@@ -7,7 +7,7 @@
 			<metric-segment-model property="agg.type" options="metricAggTypes" on-change="onTypeChange()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
 		</li>
 		<li ng-if="agg.type !== 'count'">
-			<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
+			<metric-segment-model property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
 		</li>
 		<li class="tight-form-item last" ng-if="settingsLinkText">
 			<a ng-click="toggleOptions()">{{settingsLinkText}}</a>

+ 2 - 2
public/app/plugins/datasource/elasticsearch/partials/query.editor.html

@@ -65,7 +65,7 @@
 	<div ng-repeat="agg in target.metrics">
 		<elastic-metric-agg
 			target="target" index="$index"
-			get-fields="getFields()"
+			get-fields="getFields($fieldType)"
 			on-change="queryUpdated()">
 		</elastic-metric-agg>
 	</div>
@@ -73,7 +73,7 @@
 	<div ng-repeat="agg in target.bucketAggs">
 		<elastic-bucket-agg
 			target="target" index="$index"
-			get-fields="getFields()"
+			get-fields="getFields($fieldType)"
 			on-change="queryUpdated()">
 		</elastic-bucket-agg>
 	</div>

+ 33 - 0
public/app/plugins/datasource/elasticsearch/queryBuilder.js

@@ -151,6 +151,39 @@ function (angular) {
     return query;
   };
 
+  ElasticQueryBuilder.prototype.getTermsQuery = function(queryDef) {
+    var query = {
+      "size": 0,
+      "query": {
+        "filtered": {
+          "query": {
+            "query_string": {
+              "analyze_wildcard": true,
+              "query": '$lucene_query',
+            }
+          },
+          "filter": {
+            "bool": {
+              "must": [{"range": this.getRangeFilter()}]
+            }
+          }
+        }
+      }
+    };
+    query.aggs =  {
+      "1": {
+        "terms": {
+          "field": queryDef.field,
+          "order": {
+            "_term": "asc"
+          }
+        },
+      }
+    };
+
+    return query;
+  };
+
   return ElasticQueryBuilder;
 
 });

+ 3 - 2
public/app/plugins/datasource/elasticsearch/queryCtrl.js

@@ -18,8 +18,9 @@ function (angular, _) {
       target.timeField =  $scope.datasource.timeField;
     };
 
-    $scope.getFields = function() {
-      return $scope.datasource.metricFindQuery('fields()')
+    $scope.getFields = function(type) {
+      var jsonStr = angular.toJson({find: 'fields', type: type});
+      return $scope.datasource.metricFindQuery(jsonStr)
       .then($scope.transformToSegments(false))
       .then(null, $scope.handleQueryError);
     };