2015-07-01 08:54:06 -04:00
|
|
|
define([
|
2015-12-10 11:46:19 +01:00
|
|
|
'./query_def'
|
2015-07-01 08:54:06 -04:00
|
|
|
],
|
2015-12-10 11:46:19 +01:00
|
|
|
function (queryDef) {
|
2015-07-01 08:54:06 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
2015-09-07 08:57:46 +02:00
|
|
|
function ElasticQueryBuilder(options) {
|
|
|
|
|
this.timeField = options.timeField;
|
2015-12-03 18:30:36 +01:00
|
|
|
this.esVersion = options.esVersion;
|
2015-09-07 08:57:46 +02:00
|
|
|
}
|
2015-07-01 08:54:06 -04:00
|
|
|
|
2015-09-07 08:57:46 +02:00
|
|
|
ElasticQueryBuilder.prototype.getRangeFilter = function() {
|
2015-09-04 11:17:52 +02:00
|
|
|
var filter = {};
|
2016-12-09 11:22:43 +01:00
|
|
|
filter[this.timeField] = {
|
|
|
|
|
gte: "$timeFrom",
|
|
|
|
|
lte: "$timeTo",
|
|
|
|
|
format: "epoch_millis",
|
|
|
|
|
};
|
2015-11-22 21:39:56 +09:00
|
|
|
|
2015-09-04 11:17:52 +02:00
|
|
|
return filter;
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-06 14:45:12 +02:00
|
|
|
ElasticQueryBuilder.prototype.buildTermsAgg = function(aggDef, queryNode, target) {
|
2015-10-23 12:00:20 +02:00
|
|
|
var metricRef, metric, y;
|
2015-09-06 14:45:12 +02:00
|
|
|
queryNode.terms = { "field": aggDef.field };
|
|
|
|
|
|
2015-09-07 16:35:40 +02:00
|
|
|
if (!aggDef.settings) {
|
|
|
|
|
return queryNode;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 16:59:25 +02:00
|
|
|
queryNode.terms.size = parseInt(aggDef.settings.size, 10) === 0 ? 500 : parseInt(aggDef.settings.size, 10);
|
2015-09-07 16:35:40 +02:00
|
|
|
if (aggDef.settings.orderBy !== void 0) {
|
2015-09-06 14:45:12 +02:00
|
|
|
queryNode.terms.order = {};
|
2015-09-07 16:35:40 +02:00
|
|
|
queryNode.terms.order[aggDef.settings.orderBy] = aggDef.settings.order;
|
2015-09-06 14:45:12 +02:00
|
|
|
|
|
|
|
|
// if metric ref, look it up and add it to this agg level
|
2015-09-07 16:35:40 +02:00
|
|
|
metricRef = parseInt(aggDef.settings.orderBy, 10);
|
2015-09-06 14:45:12 +02:00
|
|
|
if (!isNaN(metricRef)) {
|
|
|
|
|
for (y = 0; y < target.metrics.length; y++) {
|
|
|
|
|
metric = target.metrics[y];
|
2015-09-07 16:35:40 +02:00
|
|
|
if (metric.id === aggDef.settings.orderBy) {
|
2015-09-06 14:45:12 +02:00
|
|
|
queryNode.aggs = {};
|
|
|
|
|
queryNode.aggs[metric.id] = {};
|
|
|
|
|
queryNode.aggs[metric.id][metric.type] = {field: metric.field};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-23 07:26:42 +01:00
|
|
|
if (aggDef.settings.min_doc_count !== void 0) {
|
|
|
|
|
queryNode.terms.min_doc_count = parseInt(aggDef.settings.min_doc_count, 10);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-03 22:34:28 +02:00
|
|
|
if (aggDef.settings.missing) {
|
|
|
|
|
queryNode.terms.missing = aggDef.settings.missing;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-06 14:45:12 +02:00
|
|
|
return queryNode;
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-04 10:06:44 +01:00
|
|
|
ElasticQueryBuilder.prototype.getDateHistogramAgg = function(aggDef) {
|
|
|
|
|
var esAgg = {};
|
|
|
|
|
var settings = aggDef.settings || {};
|
|
|
|
|
esAgg.interval = settings.interval;
|
|
|
|
|
esAgg.field = this.timeField;
|
|
|
|
|
esAgg.min_doc_count = settings.min_doc_count || 0;
|
|
|
|
|
esAgg.extended_bounds = {min: "$timeFrom", max: "$timeTo"};
|
2016-12-09 11:22:43 +01:00
|
|
|
esAgg.format = "epoch_millis";
|
2015-12-04 10:06:44 +01:00
|
|
|
|
|
|
|
|
if (esAgg.interval === 'auto') {
|
2017-01-11 10:18:21 +01:00
|
|
|
esAgg.interval = "$__interval";
|
2015-09-07 16:35:40 +02:00
|
|
|
}
|
2015-12-04 10:06:44 +01:00
|
|
|
|
2016-03-03 22:34:28 +02:00
|
|
|
if (settings.missing) {
|
|
|
|
|
esAgg.missing = settings.missing;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-04 10:06:44 +01:00
|
|
|
return esAgg;
|
2015-09-07 16:35:40 +02:00
|
|
|
};
|
|
|
|
|
|
2017-03-29 13:44:01 +02:00
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-21 20:29:05 +02:00
|
|
|
ElasticQueryBuilder.prototype.getFiltersAgg = function(aggDef) {
|
2015-09-21 19:23:18 +02:00
|
|
|
var filterObj = {};
|
2015-09-21 20:29:05 +02:00
|
|
|
for (var i = 0; i < aggDef.settings.filters.length; i++) {
|
|
|
|
|
var query = aggDef.settings.filters[i].query;
|
2016-12-06 16:04:31 +01:00
|
|
|
|
|
|
|
|
filterObj[query] = {
|
|
|
|
|
query_string: {
|
|
|
|
|
query: query,
|
|
|
|
|
analyze_wildcard: true
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-09-21 19:23:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filterObj;
|
|
|
|
|
};
|
|
|
|
|
|
2015-11-05 09:56:19 +01:00
|
|
|
ElasticQueryBuilder.prototype.documentQuery = function(query) {
|
|
|
|
|
query.size = 500;
|
|
|
|
|
query.sort = {};
|
|
|
|
|
query.sort[this.timeField] = {order: 'desc', unmapped_type: 'boolean'};
|
2016-11-08 22:18:59 +01:00
|
|
|
|
|
|
|
|
// fields field not supported on ES 5.x
|
|
|
|
|
if (this.esVersion < 5) {
|
|
|
|
|
query.fields = ["*", "_source"];
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-05 09:56:19 +01:00
|
|
|
query.script_fields = {},
|
2017-05-09 08:16:48 +03:00
|
|
|
query.docvalue_fields = [this.timeField];
|
2015-11-05 09:56:19 +01:00
|
|
|
return query;
|
|
|
|
|
};
|
|
|
|
|
|
2016-09-21 08:46:59 +02:00
|
|
|
ElasticQueryBuilder.prototype.addAdhocFilters = function(query, adhocFilters) {
|
|
|
|
|
if (!adhocFilters) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 11:22:43 +01:00
|
|
|
var i, filter, condition;
|
2016-09-21 08:46:59 +02:00
|
|
|
for (i = 0; i < adhocFilters.length; i++) {
|
|
|
|
|
filter = adhocFilters[i];
|
|
|
|
|
condition = {};
|
|
|
|
|
condition[filter.key] = filter.value;
|
2017-02-21 05:01:52 +09:00
|
|
|
switch(filter.operator){
|
|
|
|
|
case "=":
|
|
|
|
|
query.query.bool.filter.push({"term": condition});
|
|
|
|
|
break;
|
|
|
|
|
case "!=":
|
|
|
|
|
query.query.bool.filter.push({"bool": {"must_not": {"term": condition}}});
|
|
|
|
|
break;
|
|
|
|
|
case "<":
|
|
|
|
|
condition[filter.key] = {"lt": filter.value};
|
|
|
|
|
query.query.bool.filter.push({"range": condition});
|
|
|
|
|
break;
|
|
|
|
|
case ">":
|
|
|
|
|
condition[filter.key] = {"gt": filter.value};
|
|
|
|
|
query.query.bool.filter.push({"range": condition});
|
|
|
|
|
break;
|
|
|
|
|
case "=~":
|
|
|
|
|
query.query.bool.filter.push({"regexp": condition});
|
|
|
|
|
break;
|
|
|
|
|
case "!~":
|
|
|
|
|
query.query.bool.filter.push({"bool": {"must_not": {"regexp": condition}}});
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-09-21 08:46:59 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-01-09 15:31:19 +01:00
|
|
|
ElasticQueryBuilder.prototype.build = function(target, adhocFilters, queryString) {
|
2015-12-03 16:32:35 +01:00
|
|
|
// make sure query has defaults;
|
|
|
|
|
target.metrics = target.metrics || [{ type: 'count', id: '1' }];
|
|
|
|
|
target.dsType = 'elasticsearch';
|
|
|
|
|
target.bucketAggs = target.bucketAggs || [{type: 'date_histogram', id: '2', settings: {interval: 'auto'}}];
|
|
|
|
|
target.timeField = this.timeField;
|
2015-09-02 17:45:41 +02:00
|
|
|
|
2015-09-21 20:29:05 +02:00
|
|
|
var i, nestedAggs, metric;
|
2016-12-09 11:40:00 +01:00
|
|
|
var query = {
|
2016-12-06 16:04:31 +01:00
|
|
|
"size": 0,
|
|
|
|
|
"query": {
|
|
|
|
|
"bool": {
|
2017-01-21 08:31:29 +01:00
|
|
|
"filter": [
|
2016-12-06 16:04:31 +01:00
|
|
|
{"range": this.getRangeFilter()},
|
2016-12-09 14:57:25 +00:00
|
|
|
{
|
|
|
|
|
"query_string": {
|
|
|
|
|
"analyze_wildcard": true,
|
2017-01-09 15:31:19 +01:00
|
|
|
"query": queryString,
|
2016-05-10 19:38:22 +02:00
|
|
|
}
|
2015-08-28 13:06:57 -04:00
|
|
|
}
|
2016-12-06 16:04:31 +01:00
|
|
|
]
|
2015-08-31 08:25:05 -04:00
|
|
|
}
|
2016-12-06 16:04:31 +01:00
|
|
|
}
|
|
|
|
|
};
|
2015-09-03 08:18:00 +02:00
|
|
|
|
2016-09-21 08:46:59 +02:00
|
|
|
this.addAdhocFilters(query, adhocFilters);
|
|
|
|
|
|
2015-11-05 09:56:19 +01:00
|
|
|
// handle document query
|
|
|
|
|
if (target.bucketAggs.length === 0) {
|
|
|
|
|
metric = target.metrics[0];
|
|
|
|
|
if (metric && metric.type !== 'raw_document') {
|
|
|
|
|
throw {message: 'Invalid query'};
|
|
|
|
|
}
|
|
|
|
|
return this.documentQuery(query, target);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-04 16:05:47 +02:00
|
|
|
nestedAggs = query;
|
2015-09-04 09:41:23 +02:00
|
|
|
|
2015-09-04 16:05:47 +02:00
|
|
|
for (i = 0; i < target.bucketAggs.length; i++) {
|
|
|
|
|
var aggDef = target.bucketAggs[i];
|
|
|
|
|
var esAgg = {};
|
2015-09-03 11:14:25 +02:00
|
|
|
|
2015-09-04 16:05:47 +02:00
|
|
|
switch(aggDef.type) {
|
|
|
|
|
case 'date_histogram': {
|
2015-12-04 10:06:44 +01:00
|
|
|
esAgg["date_histogram"] = this.getDateHistogramAgg(aggDef);
|
2015-09-04 16:05:47 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2017-03-29 13:44:01 +02:00
|
|
|
case 'histogram': {
|
|
|
|
|
esAgg["histogram"] = this.getHistogramAgg(aggDef);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-09-21 19:23:18 +02:00
|
|
|
case 'filters': {
|
2015-09-21 20:29:05 +02:00
|
|
|
esAgg["filters"] = {filters: this.getFiltersAgg(aggDef)};
|
2015-09-21 19:23:18 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-09-04 16:05:47 +02:00
|
|
|
case 'terms': {
|
2015-09-06 14:45:12 +02:00
|
|
|
this.buildTermsAgg(aggDef, esAgg, target);
|
2015-09-04 16:05:47 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2016-04-28 15:29:54 +02:00
|
|
|
case 'geohash_grid': {
|
|
|
|
|
esAgg['geohash_grid'] = {field: aggDef.field, precision: aggDef.settings.precision};
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-09-04 16:05:47 +02:00
|
|
|
}
|
2015-09-03 12:35:21 +02:00
|
|
|
|
2015-09-05 12:51:05 +02:00
|
|
|
nestedAggs.aggs = nestedAggs.aggs || {};
|
2015-09-05 12:24:14 +02:00
|
|
|
nestedAggs.aggs[aggDef.id] = esAgg;
|
2015-09-04 16:05:47 +02:00
|
|
|
nestedAggs = esAgg;
|
2015-09-03 11:14:25 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-27 10:57:44 +01:00
|
|
|
nestedAggs.aggs = {};
|
2015-09-03 16:35:11 +02:00
|
|
|
|
2017-02-27 10:57:44 +01:00
|
|
|
for (i = 0; i < target.metrics.length; i++) {
|
|
|
|
|
metric = target.metrics[i];
|
|
|
|
|
if (metric.type === 'count') {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-09-05 10:14:21 +02:00
|
|
|
|
2017-02-27 10:57:44 +01:00
|
|
|
var aggField = {};
|
|
|
|
|
var metricAgg = null;
|
2015-12-08 12:07:56 +01:00
|
|
|
|
2017-02-27 10:57:44 +01:00
|
|
|
if (queryDef.isPipelineAgg(metric.type)) {
|
|
|
|
|
if (metric.pipelineAgg && /^\d*$/.test(metric.pipelineAgg)) {
|
|
|
|
|
metricAgg = { buckets_path: metric.pipelineAgg };
|
2015-12-09 14:21:48 +01:00
|
|
|
} else {
|
2017-02-27 10:57:44 +01:00
|
|
|
continue;
|
2015-12-09 14:21:48 +01:00
|
|
|
}
|
2017-02-27 10:57:44 +01:00
|
|
|
} else {
|
|
|
|
|
metricAgg = {field: metric.field};
|
|
|
|
|
}
|
2015-12-08 12:07:56 +01:00
|
|
|
|
2017-02-27 10:57:44 +01:00
|
|
|
for (var prop in metric.settings) {
|
|
|
|
|
if (metric.settings.hasOwnProperty(prop) && metric.settings[prop] !== null) {
|
|
|
|
|
metricAgg[prop] = metric.settings[prop];
|
2015-09-05 18:31:42 +02:00
|
|
|
}
|
2017-02-27 15:27:00 +05:30
|
|
|
}
|
2017-02-27 10:57:44 +01:00
|
|
|
|
|
|
|
|
aggField[metric.type] = metricAgg;
|
|
|
|
|
nestedAggs.aggs[metric.id] = aggField;
|
2015-09-03 14:55:48 +02:00
|
|
|
}
|
2015-09-03 11:14:25 +02:00
|
|
|
|
2015-07-01 08:54:06 -04:00
|
|
|
return query;
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-22 09:31:58 +02:00
|
|
|
ElasticQueryBuilder.prototype.getTermsQuery = function(queryDef) {
|
2016-12-09 11:40:00 +01:00
|
|
|
var query = {
|
2016-12-06 16:04:31 +01:00
|
|
|
"size": 0,
|
|
|
|
|
"query": {
|
|
|
|
|
"bool": {
|
2017-01-21 08:31:29 +01:00
|
|
|
"filter": [{"range": this.getRangeFilter()}]
|
2016-05-10 19:38:22 +02:00
|
|
|
}
|
2016-10-27 18:59:24 +02:00
|
|
|
}
|
2016-12-06 16:04:31 +01:00
|
|
|
};
|
2016-10-02 16:59:25 +02:00
|
|
|
|
2016-12-06 16:04:31 +01:00
|
|
|
if (queryDef.query) {
|
2017-01-21 08:31:29 +01:00
|
|
|
query.query.bool.filter.push({
|
2016-12-06 16:04:31 +01:00
|
|
|
"query_string": {
|
|
|
|
|
"analyze_wildcard": true,
|
|
|
|
|
"query": queryDef.query,
|
2015-09-22 09:31:58 +02:00
|
|
|
}
|
2016-12-06 16:04:31 +01:00
|
|
|
});
|
2016-05-10 19:38:22 +02:00
|
|
|
}
|
2017-03-29 16:03:15 +02:00
|
|
|
|
2017-01-25 11:29:41 +00:00
|
|
|
var size = 500;
|
2017-03-29 16:03:15 +02:00
|
|
|
if (queryDef.size) {
|
2017-01-25 11:29:41 +00:00
|
|
|
size = queryDef.size;
|
|
|
|
|
}
|
2017-03-29 16:03:15 +02:00
|
|
|
|
2015-09-22 09:31:58 +02:00
|
|
|
query.aggs = {
|
|
|
|
|
"1": {
|
|
|
|
|
"terms": {
|
|
|
|
|
"field": queryDef.field,
|
2017-01-25 11:29:41 +00:00
|
|
|
"size": size,
|
2015-09-22 09:31:58 +02:00
|
|
|
"order": {
|
|
|
|
|
"_term": "asc"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return query;
|
|
|
|
|
};
|
|
|
|
|
|
2015-07-01 08:54:06 -04:00
|
|
|
return ElasticQueryBuilder;
|
|
|
|
|
});
|