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

pull/2585/merge
Torkel Ödegaard 10 years ago
parent 7e9f11ea1c
commit 590b155c6c
  1. 40
      public/app/plugins/datasource/elasticsearch/datasource.js
  2. 39
      public/app/plugins/datasource/elasticsearch/queryCtrl.js
  3. 2
      public/test/specs/elasticsearch-querybuilder-specs.js
  4. 70
      public/test/specs/elasticsearch-specs.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);

@ -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);
};
};

@ -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;
});

@ -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');
});
});

Loading…
Cancel
Save