Commit bc3c3942 by Torkel Ödegaard

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

parent 0ef8e086
...@@ -39,7 +39,7 @@ function (angular, _, queryDef) { ...@@ -39,7 +39,7 @@ function (angular, _, queryDef) {
case 'date_histogram': case 'date_histogram':
case 'terms': { case 'terms': {
delete $scope.agg.query; delete $scope.agg.query;
$scope.agg.type = 'select field'; $scope.agg.field = 'select field';
break; break;
} }
case 'filters': { case 'filters': {
...@@ -120,6 +120,14 @@ function (angular, _, queryDef) { ...@@ -120,6 +120,14 @@ function (angular, _, queryDef) {
$scope.orderByOptions = queryDef.getOrderByOptions($scope.target); $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() { $scope.addBucketAgg = function() {
// if last is date histogram add it before // if last is date histogram add it before
var lastBucket = bucketAggs[bucketAggs.length - 1]; var lastBucket = bucketAggs[bucketAggs.length - 1];
...@@ -133,7 +141,7 @@ function (angular, _, queryDef) { ...@@ -133,7 +141,7 @@ function (angular, _, queryDef) {
return parseInt(val.id) > max ? parseInt(val.id) : max; return parseInt(val.id) > max ? parseInt(val.id) : max;
}, 0); }, 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(); $scope.onChange();
}; };
......
...@@ -14,7 +14,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes ...@@ -14,7 +14,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
var module = angular.module('grafana.services'); var module = angular.module('grafana.services');
module.factory('ElasticDatasource', function($q, backendSrv, templateSrv) { module.factory('ElasticDatasource', function($q, backendSrv, templateSrv, timeSrv) {
function ElasticDatasource(datasource) { function ElasticDatasource(datasource) {
this.type = 'elasticsearch'; this.type = 'elasticsearch';
...@@ -168,7 +168,6 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes ...@@ -168,7 +168,6 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
payload = payload.replace(/\$interval/g, options.interval); payload = payload.replace(/\$interval/g, options.interval);
payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf()); payload = payload.replace(/\$timeFrom/g, options.range.from.valueOf());
payload = payload.replace(/\$timeTo/g, options.range.to.valueOf()); payload = payload.replace(/\$timeTo/g, options.range.to.valueOf());
payload = payload.replace(/\$maxDataPoints/g, options.maxDataPoints);
payload = templateSrv.replace(payload, options.scopedVars); payload = templateSrv.replace(payload, options.scopedVars);
return this._post('/_msearch?search_type=count', payload).then(function(res) { return this._post('/_msearch?search_type=count', payload).then(function(res) {
...@@ -176,9 +175,17 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes ...@@ -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) { return this._get('/_mapping').then(function(res) {
var fields = {}; var fields = {};
var typeMap = {
'float': 'number',
'double': 'number',
'integer': 'number',
'long': 'number',
'date': 'date',
'string': 'string',
};
for (var indexName in res) { for (var indexName in res) {
var index = res[indexName]; var index = res[indexName];
...@@ -188,21 +195,53 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes ...@@ -188,21 +195,53 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
var properties = mappings[typeName].properties; var properties = mappings[typeName].properties;
for (var field in properties) { for (var field in properties) {
var prop = properties[field]; var prop = properties[field];
if (query.type && typeMap[prop.type] !== query.type) {
continue;
}
if (prop.type && field[0] !== '_') { if (prop.type && field[0] !== '_') {
fields[field] = prop; fields[field] = {text: field, type: prop.type};
} }
} }
} }
} }
fields = _.map(_.keys(fields), function(field) { // transform to array
return {text: field}; 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) { ElasticDatasource.prototype.getDashboard = function(id) {
return this._get('/dashboard/' + id) return this._get('/dashboard/' + id)
.then(function(result) { .then(function(result) {
......
...@@ -70,6 +70,10 @@ function (angular, _, queryDef) { ...@@ -70,6 +70,10 @@ function (angular, _, queryDef) {
$scope.onChange(); $scope.onChange();
}; };
$scope.getFieldsInternal = function() {
return $scope.getFields({$fieldType: 'number'});
};
$scope.addMetricAgg = function() { $scope.addMetricAgg = function() {
var addIndex = metricAggs.length; var addIndex = metricAggs.length;
......
...@@ -8,7 +8,7 @@ ...@@ -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> <metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onTypeChanged()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
</li> </li>
<li ng-if="agg.field"> <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>
<li ng-if="!agg.field"> <li ng-if="!agg.field">
<span class="tight-form-item tight-form-item-xxlarge">&nbsp;</span> <span class="tight-form-item tight-form-item-xxlarge">&nbsp;</span>
......
...@@ -7,7 +7,7 @@ ...@@ -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> <metric-segment-model property="agg.type" options="metricAggTypes" on-change="onTypeChange()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
</li> </li>
<li ng-if="agg.type !== 'count'"> <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>
<li class="tight-form-item last" ng-if="settingsLinkText"> <li class="tight-form-item last" ng-if="settingsLinkText">
<a ng-click="toggleOptions()">{{settingsLinkText}}</a> <a ng-click="toggleOptions()">{{settingsLinkText}}</a>
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
<div ng-repeat="agg in target.metrics"> <div ng-repeat="agg in target.metrics">
<elastic-metric-agg <elastic-metric-agg
target="target" index="$index" target="target" index="$index"
get-fields="getFields()" get-fields="getFields($fieldType)"
on-change="queryUpdated()"> on-change="queryUpdated()">
</elastic-metric-agg> </elastic-metric-agg>
</div> </div>
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
<div ng-repeat="agg in target.bucketAggs"> <div ng-repeat="agg in target.bucketAggs">
<elastic-bucket-agg <elastic-bucket-agg
target="target" index="$index" target="target" index="$index"
get-fields="getFields()" get-fields="getFields($fieldType)"
on-change="queryUpdated()"> on-change="queryUpdated()">
</elastic-bucket-agg> </elastic-bucket-agg>
</div> </div>
......
...@@ -151,6 +151,39 @@ function (angular) { ...@@ -151,6 +151,39 @@ function (angular) {
return query; 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; return ElasticQueryBuilder;
}); });
...@@ -18,8 +18,9 @@ function (angular, _) { ...@@ -18,8 +18,9 @@ function (angular, _) {
target.timeField = $scope.datasource.timeField; target.timeField = $scope.datasource.timeField;
}; };
$scope.getFields = function() { $scope.getFields = function(type) {
return $scope.datasource.metricFindQuery('fields()') var jsonStr = angular.toJson({find: 'fields', type: type});
return $scope.datasource.metricFindQuery(jsonStr)
.then($scope.transformToSegments(false)) .then($scope.transformToSegments(false))
.then(null, $scope.handleQueryError); .then(null, $scope.handleQueryError);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment