commit
31836a6302
37
src/fixtures/agg_resp/range.js
Normal file
37
src/fixtures/agg_resp/range.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
module.exports = {
|
||||
"took": 35,
|
||||
"timed_out": false,
|
||||
"_shards": {
|
||||
"total": 7,
|
||||
"successful": 7,
|
||||
"failed": 0
|
||||
},
|
||||
"hits": {
|
||||
"total": 218512,
|
||||
"max_score": 0,
|
||||
"hits": []
|
||||
},
|
||||
"aggregations": {
|
||||
"1": {
|
||||
"buckets": {
|
||||
"*-1024.0": {
|
||||
"to": 1024,
|
||||
"to_as_string": "1024.0",
|
||||
"doc_count": 20904
|
||||
},
|
||||
"1024.0-2560.0": {
|
||||
"from": 1024,
|
||||
"from_as_string": "1024.0",
|
||||
"to": 2560,
|
||||
"to_as_string": "2560.0",
|
||||
"doc_count": 23358
|
||||
},
|
||||
"2560.0-*": {
|
||||
"from": 2560,
|
||||
"from_as_string": "2560.0",
|
||||
"doc_count": 174250
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -36,6 +36,10 @@ describe('plugins/elasticsearch', function () {
|
|||
|
||||
|
||||
function testRoute(options) {
|
||||
if (typeof options.payload === 'object') {
|
||||
options.payload = JSON.stringify(options.payload);
|
||||
}
|
||||
|
||||
var statusCode = options.statusCode || 200;
|
||||
describe(format('%s %s', options.method, options.url), function () {
|
||||
it('should should return ' + statusCode, function (done) {
|
||||
|
@ -67,7 +71,7 @@ describe('plugins/elasticsearch', function () {
|
|||
testRoute({
|
||||
method: 'POST',
|
||||
url: '/elasticsearch/.kibana',
|
||||
payload: '{settings: {number_of_shards: 1, number_of_replicas: 1}}',
|
||||
payload: {settings: { number_of_shards: 1, number_of_replicas: 1 }},
|
||||
statusCode: 201
|
||||
});
|
||||
|
||||
|
@ -91,19 +95,19 @@ describe('plugins/elasticsearch', function () {
|
|||
testRoute({
|
||||
method: 'POST',
|
||||
url: '/elasticsearch/.kibana/index-pattern/_search?fields=',
|
||||
payload: '{query: {match_all: {}}, size: 2147483647}'
|
||||
payload: {query: {match_all: {}}, size: 2147483647}
|
||||
});
|
||||
|
||||
testRoute({
|
||||
method: 'POST',
|
||||
url: '/elasticsearch/.kibana/__kibanaQueryValidator/_validate/query?explain=true&ignore_unavailable=true',
|
||||
payload: '{query: {query_string: {analyze_wildcard: true, query: "*"}}}'
|
||||
payload: {query: {query_string: {analyze_wildcard: true, query: '*'}}}
|
||||
});
|
||||
|
||||
testRoute({
|
||||
method: 'POST',
|
||||
url: '/elasticsearch/_mget?timeout=0&ignore_unavailable=true&preference=1429574531063',
|
||||
payload: '{docs: [{_index: ".kibana", _type: "index-pattern", _id: "[logstash-]YYYY.MM.DD"}]}'
|
||||
payload: {docs: [{_index: '.kibana', _type: 'index-pattern', _id: '[logstash-]YYYY.MM.DD'}]}
|
||||
});
|
||||
|
||||
testRoute({
|
||||
|
|
|
@ -267,16 +267,18 @@ define(function (require) {
|
|||
return this.params.field;
|
||||
};
|
||||
|
||||
AggConfig.prototype.fieldFormatter = function (contentType) {
|
||||
AggConfig.prototype.fieldFormatter = function (contentType, defaultFormat) {
|
||||
var format = this.type && this.type.getFormat(this);
|
||||
if (format) return format.getConverterFor(contentType);
|
||||
return this.fieldOwnFormatter(contentType, defaultFormat);
|
||||
};
|
||||
|
||||
AggConfig.prototype.fieldOwnFormatter = function (contentType, defaultFormat) {
|
||||
var field = this.field();
|
||||
var format = field && field.format;
|
||||
var strFormat = fieldFormats.getDefaultInstance('string');
|
||||
|
||||
if (this.type) {
|
||||
format = this.type.getFormat(this) || format;
|
||||
}
|
||||
|
||||
return (format || strFormat).getConverterFor(contentType);
|
||||
if (!format) format = defaultFormat;
|
||||
if (!format) format = fieldFormats.getDefaultInstance('string');
|
||||
return format.getConverterFor(contentType);
|
||||
};
|
||||
|
||||
AggConfig.prototype.fieldName = function () {
|
||||
|
|
|
@ -59,7 +59,7 @@ define(function (require) {
|
|||
}
|
||||
|
||||
// iterate through all the buckets
|
||||
_.each(extractBuckets(data[agg.id]), function (bucket) {
|
||||
_.each(extractBuckets(data[agg.id], agg), function (bucket) {
|
||||
|
||||
var _record = _.flattenDeep([record, bucket.key]);
|
||||
_.each(metrics, function (metric) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
return function (bucket) {
|
||||
return function (bucket, agg) {
|
||||
if (bucket && _.isPlainObject(bucket.buckets)) {
|
||||
return _.map(bucket.buckets, function (value, key) {
|
||||
var item = _.cloneDeep(value);
|
||||
item.key = key;
|
||||
item.key = agg ? agg.getKey(value, key) : key;
|
||||
return item;
|
||||
});
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ define(function (require) {
|
|||
return function transformAggregationProvider(Private) {
|
||||
var AggConfigResult = require('ui/Vis/AggConfigResult');
|
||||
return function transformAggregation(agg, metric, aggData, parent) {
|
||||
return _.map(extractBuckets(aggData), function (bucket) {
|
||||
return _.map(extractBuckets(aggData, agg), function (bucket) {
|
||||
var aggConfigResult = new AggConfigResult(
|
||||
agg,
|
||||
parent && parent.aggConfigResult,
|
||||
|
|
|
@ -65,11 +65,11 @@ define(function (require) {
|
|||
}
|
||||
|
||||
// map the split aggregations into rows.
|
||||
var rows = _.map(extractBuckets(aggData), function (bucket) {
|
||||
var rows = _.map(extractBuckets(aggData, firstAgg), function (bucket) {
|
||||
var agg = firstAgg._next;
|
||||
var split = buildSplit(agg, metric, bucket[agg.id]);
|
||||
// Since splits display labels we need to set it.
|
||||
split.label = firstAgg.fieldFormatter()(bucket.key);
|
||||
split.label = firstAgg.fieldFormatter()(agg.getKey(bucket));
|
||||
|
||||
var displayName = firstAgg.fieldDisplayName();
|
||||
if (!_.isEmpty(displayName)) split.label += ': ' + displayName;
|
||||
|
|
58
src/ui/public/agg_types/__tests__/buckets/_range.js
Normal file
58
src/ui/public/agg_types/__tests__/buckets/_range.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
describe('Range Agg', function () {
|
||||
var _ = require('lodash');
|
||||
var ngMock = require('ngMock');
|
||||
var expect = require('expect.js');
|
||||
var values = require('lodash').values;
|
||||
|
||||
var resp = require('fixtures/agg_resp/range');
|
||||
var buckets = values(resp.aggregations[1].buckets);
|
||||
|
||||
var range;
|
||||
var Vis;
|
||||
var indexPattern;
|
||||
|
||||
beforeEach(ngMock.module('kibana'));
|
||||
beforeEach(ngMock.inject(function (Private) {
|
||||
range = Private(require('ui/agg_types/index')).byName.range;
|
||||
Vis = Private(require('ui/Vis'));
|
||||
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
|
||||
|
||||
var BytesFormat = Private(require('ui/registry/field_formats')).byId.bytes;
|
||||
|
||||
indexPattern.fieldFormatMap.bytes = new BytesFormat({
|
||||
pattern: '0,0.[000] b'
|
||||
});
|
||||
|
||||
indexPattern._indexFields();
|
||||
}));
|
||||
|
||||
describe('formating', function () {
|
||||
it('formats bucket keys properly', function () {
|
||||
var vis = new Vis(indexPattern, {
|
||||
type: 'histogram',
|
||||
aggs: [
|
||||
{
|
||||
type: 'range',
|
||||
schema: 'segment',
|
||||
params: {
|
||||
field: 'bytes',
|
||||
ranges: [
|
||||
{ from: 0, to: 1000 },
|
||||
{ from: 1000, to: 2000 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var agg = vis.aggs.byTypeName.range[0];
|
||||
var format = function (val) {
|
||||
return agg.fieldFormatter()(agg.getKey(val));
|
||||
};
|
||||
expect(format(buckets[0])).to.be('-∞ to 1 KB');
|
||||
expect(format(buckets[1])).to.be('1 KB to 2.5 KB');
|
||||
expect(format(buckets[2])).to.be('2.5 KB to +∞');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
|
@ -34,7 +34,7 @@ describe('AggConfig Filters', function () {
|
|||
});
|
||||
|
||||
var aggConfig = vis.aggs.byTypeName.range[0];
|
||||
var filter = createFilter(aggConfig, '1024.0-2048.0');
|
||||
var filter = createFilter(aggConfig, { gte: 1024, lt: 2048.0 });
|
||||
expect(filter).to.have.property('range');
|
||||
expect(filter).to.have.property('meta');
|
||||
expect(filter.meta).to.have.property('index', indexPattern.id);
|
||||
|
|
|
@ -6,6 +6,7 @@ describe('AggTypesComponent', function () {
|
|||
require('./AggParams');
|
||||
require('./bucketCountBetween');
|
||||
require('./buckets/_histogram');
|
||||
require('./buckets/_range');
|
||||
|
||||
describe('bucket aggs', function () {
|
||||
var bucketAggs;
|
||||
|
|
|
@ -2,13 +2,7 @@ define(function (require) {
|
|||
var buildRangeFilter = require('ui/filter_manager/lib/range');
|
||||
return function createRangeFilterProvider(Private) {
|
||||
return function (aggConfig, key) {
|
||||
var splits = key.split(/\-/);
|
||||
var gte = Number(splits[0]);
|
||||
var lt = Number(splits[1]);
|
||||
return buildRangeFilter(aggConfig.params.field, {
|
||||
gte: gte,
|
||||
lt: lt
|
||||
}, aggConfig.vis.indexPattern);
|
||||
return buildRangeFilter(aggConfig.params.field, key, aggConfig.vis.indexPattern);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
@ -14,12 +14,7 @@ define(function (require) {
|
|||
title: 'Date Range',
|
||||
createFilter: createFilter,
|
||||
getKey: function (bucket, key, agg) {
|
||||
var formatter;
|
||||
if (agg.field()) {
|
||||
formatter = agg.field().format.getConverterFor('text');
|
||||
} else {
|
||||
formatter = fieldFormats.getDefaultInstance('date').getConverterFor('text');
|
||||
}
|
||||
var formatter = agg.fieldOwnFormatter('text', fieldFormats.getDefaultInstance('date'));
|
||||
return dateRange.toString(bucket, formatter);
|
||||
},
|
||||
getFormat: function () {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
define(function (require) {
|
||||
return function RangeAggDefinition(Private) {
|
||||
var _ = require('lodash');
|
||||
var moment = require('moment');
|
||||
var angular = require('angular');
|
||||
var BucketAggType = Private(require('ui/agg_types/buckets/_bucket_agg_type'));
|
||||
var createFilter = Private(require('ui/agg_types/buckets/create_filter/range'));
|
||||
var FieldFormat = Private(require('ui/index_patterns/_field_format/FieldFormat'));
|
||||
|
||||
|
||||
return new BucketAggType({
|
||||
name: 'range',
|
||||
|
@ -13,6 +13,24 @@ define(function (require) {
|
|||
makeLabel: function (aggConfig) {
|
||||
return aggConfig.params.field.displayName + ' ranges';
|
||||
},
|
||||
getKey: function (bucket, key, agg) {
|
||||
let range = { gte: bucket.from, lt: bucket.to };
|
||||
|
||||
if (range.gte == null) range.gte = -Infinity;
|
||||
if (range.lt == null) range.lt = +Infinity;
|
||||
|
||||
return range;
|
||||
},
|
||||
getFormat: function (agg) {
|
||||
if (agg.$$rangeAggTypeFormat) return agg.$$rangeAggTypeFormat;
|
||||
|
||||
var RangeFormat = FieldFormat.from(function (range) {
|
||||
var format = agg.fieldOwnFormatter();
|
||||
return `${format(range.gte)} to ${format(range.lt)}`;
|
||||
});
|
||||
|
||||
return (this.$$rangeAggTypeFormat = new RangeFormat());
|
||||
},
|
||||
params: [
|
||||
{
|
||||
name: 'field',
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
define(function (require) {
|
||||
var _ = require('lodash');
|
||||
var {has} = require('lodash');
|
||||
return function mapRangeProvider(Promise, courier) {
|
||||
return function (filter) {
|
||||
var key;
|
||||
var value;
|
||||
var from;
|
||||
var to;
|
||||
var field;
|
||||
if (filter.range) {
|
||||
return courier
|
||||
.indexPatterns
|
||||
.get(filter.meta.index).then(function (indexPattern) {
|
||||
key = _.keys(filter.range)[0];
|
||||
field = indexPattern.fields.byName[key];
|
||||
from = (filter.range[key].gte != null) ? filter.range[key].gte : filter.range[key].gt;
|
||||
from = field.format.convert(from);
|
||||
to = (filter.range[key].lte != null) ? filter.range[key].lte : filter.range[key].lt;
|
||||
to = field.format.convert(to);
|
||||
value = from + ' to ' + to;
|
||||
return { key: key, value: value };
|
||||
});
|
||||
}
|
||||
return Promise.reject(filter);
|
||||
if (!filter.range) return Promise.reject(filter);
|
||||
|
||||
return courier
|
||||
.indexPatterns
|
||||
.get(filter.meta.index)
|
||||
.then(function (indexPattern) {
|
||||
var key = Object.keys(filter.range)[0];
|
||||
var convert = indexPattern.fields.byName[key].format.getConverterFor('text');
|
||||
var range = filter.range[key];
|
||||
|
||||
var left = has(range, 'gte') ? range.gte : range.gt;
|
||||
if (left == null) left = -Infinity;
|
||||
|
||||
var right = has(range, 'lte') ? range.lte : range.lt;
|
||||
if (right == null) right = Infinity;
|
||||
|
||||
return {
|
||||
key: key,
|
||||
value: `${convert(left)} to ${convert(right)}`
|
||||
};
|
||||
});
|
||||
|
||||
};
|
||||
};
|
||||
});
|
||||
|
|
|
@ -21,6 +21,15 @@ define(function (require) {
|
|||
contentTypes.setup(self);
|
||||
}
|
||||
|
||||
FieldFormat.from = function (converter) {
|
||||
_.class(FieldFormatFromConverter).inherits(FieldFormat);
|
||||
function FieldFormatFromConverter(params) {
|
||||
FieldFormatFromConverter.Super.call(this, params);
|
||||
}
|
||||
FieldFormatFromConverter.prototype._convert = converter;
|
||||
return FieldFormatFromConverter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a raw value to a formated string
|
||||
* @param {any} value
|
||||
|
|
|
@ -12,6 +12,8 @@ define(function (require) {
|
|||
}
|
||||
|
||||
Numeral.prototype._convert = function (val) {
|
||||
if (val === -Infinity) return '-∞';
|
||||
if (val === +Infinity) return '+∞';
|
||||
if (typeof val !== 'number') {
|
||||
val = parseFloat(val);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue