Adds the ability to specify a format on composite date_histogram source (#28310)
This commit adds the ability to specify a date format on the `date_histogram` composite source. If the format is defined, the key for the source is returned as a formatted date. Closes #27923
This commit is contained in:
parent
d31e964a86
commit
19cfc25873
|
@ -225,7 +225,41 @@ Note that fractional time values are not supported, but you can address this by
|
||||||
time unit (e.g., `1.5h` could instead be specified as `90m`).
|
time unit (e.g., `1.5h` could instead be specified as `90m`).
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
===== Time Zone
|
====== Format
|
||||||
|
|
||||||
|
Internally, a date is represented as a 64 bit number representing a timestamp in milliseconds-since-the-epoch.
|
||||||
|
These timestamps are returned as the bucket keys. It is possible to return a formatted date string instead using
|
||||||
|
the format specified with the format parameter:
|
||||||
|
|
||||||
|
[source,js]
|
||||||
|
--------------------------------------------------
|
||||||
|
GET /_search
|
||||||
|
{
|
||||||
|
"aggs" : {
|
||||||
|
"my_buckets": {
|
||||||
|
"composite" : {
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"date": {
|
||||||
|
"date_histogram" : {
|
||||||
|
"field": "timestamp",
|
||||||
|
"interval": "1d",
|
||||||
|
"format": "yyyy-MM-dd" <1>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--------------------------------------------------
|
||||||
|
// CONSOLE
|
||||||
|
|
||||||
|
<1> Supports expressive date <<date-format-pattern,format pattern>>
|
||||||
|
|
||||||
|
[float]
|
||||||
|
====== Time Zone
|
||||||
|
|
||||||
Date-times are stored in Elasticsearch in UTC. By default, all bucketing and
|
Date-times are stored in Elasticsearch in UTC. By default, all bucketing and
|
||||||
rounding is also done in UTC. The `time_zone` parameter can be used to indicate
|
rounding is also done in UTC. The `time_zone` parameter can be used to indicate
|
||||||
|
|
|
@ -7,6 +7,8 @@ setup:
|
||||||
mappings:
|
mappings:
|
||||||
doc:
|
doc:
|
||||||
properties:
|
properties:
|
||||||
|
date:
|
||||||
|
type: date
|
||||||
keyword:
|
keyword:
|
||||||
type: keyword
|
type: keyword
|
||||||
long:
|
long:
|
||||||
|
@ -40,6 +42,20 @@ setup:
|
||||||
id: 4
|
id: 4
|
||||||
body: { "keyword": "bar", "long": [1000, 0] }
|
body: { "keyword": "bar", "long": [1000, 0] }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: test
|
||||||
|
type: doc
|
||||||
|
id: 5
|
||||||
|
body: { "date": "2017-10-20T03:08:45" }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: test
|
||||||
|
type: doc
|
||||||
|
id: 6
|
||||||
|
body: { "date": "2017-10-21T07:00:00" }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
indices.refresh:
|
indices.refresh:
|
||||||
index: [test]
|
index: [test]
|
||||||
|
@ -66,7 +82,7 @@ setup:
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
- match: {hits.total: 4}
|
- match: {hits.total: 6}
|
||||||
- length: { aggregations.test.buckets: 2 }
|
- length: { aggregations.test.buckets: 2 }
|
||||||
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
||||||
- match: { aggregations.test.buckets.0.doc_count: 3 }
|
- match: { aggregations.test.buckets.0.doc_count: 3 }
|
||||||
|
@ -104,7 +120,7 @@ setup:
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
- match: {hits.total: 4}
|
- match: {hits.total: 6}
|
||||||
- length: { aggregations.test.buckets: 5 }
|
- length: { aggregations.test.buckets: 5 }
|
||||||
- match: { aggregations.test.buckets.0.key.long: 0}
|
- match: { aggregations.test.buckets.0.key.long: 0}
|
||||||
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
||||||
|
@ -154,7 +170,7 @@ setup:
|
||||||
]
|
]
|
||||||
after: { "long": 20, "kw": "foo" }
|
after: { "long": 20, "kw": "foo" }
|
||||||
|
|
||||||
- match: {hits.total: 4}
|
- match: {hits.total: 6}
|
||||||
- length: { aggregations.test.buckets: 2 }
|
- length: { aggregations.test.buckets: 2 }
|
||||||
- match: { aggregations.test.buckets.0.key.long: 100 }
|
- match: { aggregations.test.buckets.0.key.long: 100 }
|
||||||
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
- match: { aggregations.test.buckets.0.key.kw: "bar" }
|
||||||
|
@ -188,7 +204,7 @@ setup:
|
||||||
]
|
]
|
||||||
after: { "kw": "delta" }
|
after: { "kw": "delta" }
|
||||||
|
|
||||||
- match: {hits.total: 4}
|
- match: {hits.total: 6}
|
||||||
- length: { aggregations.test.buckets: 1 }
|
- length: { aggregations.test.buckets: 1 }
|
||||||
- match: { aggregations.test.buckets.0.key.kw: "foo" }
|
- match: { aggregations.test.buckets.0.key.kw: "foo" }
|
||||||
- match: { aggregations.test.buckets.0.doc_count: 2 }
|
- match: { aggregations.test.buckets.0.doc_count: 2 }
|
||||||
|
@ -220,3 +236,62 @@ setup:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
---
|
||||||
|
"Composite aggregation with format":
|
||||||
|
- skip:
|
||||||
|
version: " - 6.99.99"
|
||||||
|
reason: this uses a new option (format) added in 7.0.0
|
||||||
|
|
||||||
|
- do:
|
||||||
|
search:
|
||||||
|
index: test
|
||||||
|
body:
|
||||||
|
aggregations:
|
||||||
|
test:
|
||||||
|
composite:
|
||||||
|
sources: [
|
||||||
|
{
|
||||||
|
"date": {
|
||||||
|
"date_histogram": {
|
||||||
|
"field": "date",
|
||||||
|
"interval": "1d",
|
||||||
|
"format": "yyyy-MM-dd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- match: {hits.total: 6}
|
||||||
|
- length: { aggregations.test.buckets: 2 }
|
||||||
|
- match: { aggregations.test.buckets.0.key.date: "2017-10-20" }
|
||||||
|
- match: { aggregations.test.buckets.0.doc_count: 1 }
|
||||||
|
- match: { aggregations.test.buckets.1.key.date: "2017-10-21" }
|
||||||
|
- match: { aggregations.test.buckets.1.doc_count: 1 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
search:
|
||||||
|
index: test
|
||||||
|
body:
|
||||||
|
aggregations:
|
||||||
|
test:
|
||||||
|
composite:
|
||||||
|
after: {
|
||||||
|
date: "2017-10-20"
|
||||||
|
}
|
||||||
|
sources: [
|
||||||
|
{
|
||||||
|
"date": {
|
||||||
|
"date_histogram": {
|
||||||
|
"field": "date",
|
||||||
|
"interval": "1d",
|
||||||
|
"format": "yyyy-MM-dd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
- match: {hits.total: 6}
|
||||||
|
- length: { aggregations.test.buckets: 1 }
|
||||||
|
- match: { aggregations.test.buckets.0.key.date: "2017-10-21" }
|
||||||
|
- match: { aggregations.test.buckets.0.doc_count: 1 }
|
||||||
|
|
|
@ -147,17 +147,15 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
|
||||||
Sort sort = indexSortConfig.buildIndexSort(shardContext::fieldMapper, shardContext::getForField);
|
Sort sort = indexSortConfig.buildIndexSort(shardContext::fieldMapper, shardContext::getForField);
|
||||||
System.arraycopy(sort.getSort(), 0, sortFields, 0, sortFields.length);
|
System.arraycopy(sort.getSort(), 0, sortFields, 0, sortFields.length);
|
||||||
}
|
}
|
||||||
List<String> sourceNames = new ArrayList<>();
|
|
||||||
for (int i = 0; i < configs.length; i++) {
|
for (int i = 0; i < configs.length; i++) {
|
||||||
configs[i] = sources.get(i).build(context, i, configs.length, sortFields[i]);
|
configs[i] = sources.get(i).build(context, i, configs.length, sortFields[i]);
|
||||||
sourceNames.add(sources.get(i).name());
|
|
||||||
if (configs[i].valuesSource().needsScores()) {
|
if (configs[i].valuesSource().needsScores()) {
|
||||||
throw new IllegalArgumentException("[sources] cannot access _score");
|
throw new IllegalArgumentException("[sources] cannot access _score");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final CompositeKey afterKey;
|
final CompositeKey afterKey;
|
||||||
if (after != null) {
|
if (after != null) {
|
||||||
if (after.size() != sources.size()) {
|
if (after.size() != configs.length) {
|
||||||
throw new IllegalArgumentException("[after] has " + after.size() +
|
throw new IllegalArgumentException("[after] has " + after.size() +
|
||||||
" value(s) but [sources] has " + sources.size());
|
" value(s) but [sources] has " + sources.size());
|
||||||
}
|
}
|
||||||
|
@ -179,7 +177,7 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder<Comp
|
||||||
} else {
|
} else {
|
||||||
afterKey = null;
|
afterKey = null;
|
||||||
}
|
}
|
||||||
return new CompositeAggregationFactory(name, context, parent, subfactoriesBuilder, metaData, size, configs, sourceNames, afterKey);
|
return new CompositeAggregationFactory(name, context, parent, subfactoriesBuilder, metaData, size, configs, afterKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,14 @@ import java.util.Map;
|
||||||
class CompositeAggregationFactory extends AggregatorFactory<CompositeAggregationFactory> {
|
class CompositeAggregationFactory extends AggregatorFactory<CompositeAggregationFactory> {
|
||||||
private final int size;
|
private final int size;
|
||||||
private final CompositeValuesSourceConfig[] sources;
|
private final CompositeValuesSourceConfig[] sources;
|
||||||
private final List<String> sourceNames;
|
|
||||||
private final CompositeKey afterKey;
|
private final CompositeKey afterKey;
|
||||||
|
|
||||||
CompositeAggregationFactory(String name, SearchContext context, AggregatorFactory<?> parent,
|
CompositeAggregationFactory(String name, SearchContext context, AggregatorFactory<?> parent,
|
||||||
AggregatorFactories.Builder subFactoriesBuilder, Map<String, Object> metaData,
|
AggregatorFactories.Builder subFactoriesBuilder, Map<String, Object> metaData,
|
||||||
int size, CompositeValuesSourceConfig[] sources,
|
int size, CompositeValuesSourceConfig[] sources, CompositeKey afterKey) throws IOException {
|
||||||
List<String> sourceNames, CompositeKey afterKey) throws IOException {
|
|
||||||
super(name, context, parent, subFactoriesBuilder, metaData);
|
super(name, context, parent, subFactoriesBuilder, metaData);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
this.sourceNames = sourceNames;
|
|
||||||
this.afterKey = afterKey;
|
this.afterKey = afterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +47,6 @@ class CompositeAggregationFactory extends AggregatorFactory<CompositeAggregation
|
||||||
protected Aggregator createInternal(Aggregator parent, boolean collectsFromSingleBucket,
|
protected Aggregator createInternal(Aggregator parent, boolean collectsFromSingleBucket,
|
||||||
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
|
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) throws IOException {
|
||||||
return new CompositeAggregator(name, factories, context, parent, pipelineAggregators, metaData,
|
return new CompositeAggregator(name, factories, context, parent, pipelineAggregators, metaData,
|
||||||
size, sources, sourceNames, afterKey);
|
size, sources, afterKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.search.Query;
|
||||||
import org.apache.lucene.search.Scorer;
|
import org.apache.lucene.search.Scorer;
|
||||||
import org.apache.lucene.search.Weight;
|
import org.apache.lucene.search.Weight;
|
||||||
import org.apache.lucene.util.RoaringDocIdSet;
|
import org.apache.lucene.util.RoaringDocIdSet;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.Aggregator;
|
import org.elasticsearch.search.aggregations.Aggregator;
|
||||||
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||||
|
@ -43,11 +44,13 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
final class CompositeAggregator extends BucketsAggregator {
|
final class CompositeAggregator extends BucketsAggregator {
|
||||||
private final int size;
|
private final int size;
|
||||||
private final CompositeValuesSourceConfig[] sources;
|
private final CompositeValuesSourceConfig[] sources;
|
||||||
private final List<String> sourceNames;
|
private final List<String> sourceNames;
|
||||||
|
private final List<DocValueFormat> formats;
|
||||||
private final boolean canEarlyTerminate;
|
private final boolean canEarlyTerminate;
|
||||||
|
|
||||||
private final TreeMap<Integer, Integer> keys;
|
private final TreeMap<Integer, Integer> keys;
|
||||||
|
@ -59,12 +62,12 @@ final class CompositeAggregator extends BucketsAggregator {
|
||||||
|
|
||||||
CompositeAggregator(String name, AggregatorFactories factories, SearchContext context, Aggregator parent,
|
CompositeAggregator(String name, AggregatorFactories factories, SearchContext context, Aggregator parent,
|
||||||
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData,
|
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData,
|
||||||
int size, CompositeValuesSourceConfig[] sources, List<String> sourceNames,
|
int size, CompositeValuesSourceConfig[] sources, CompositeKey rawAfterKey) throws IOException {
|
||||||
CompositeKey rawAfterKey) throws IOException {
|
|
||||||
super(name, factories, context, parent, pipelineAggregators, metaData);
|
super(name, factories, context, parent, pipelineAggregators, metaData);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.sources = sources;
|
this.sources = sources;
|
||||||
this.sourceNames = sourceNames;
|
this.sourceNames = Arrays.stream(sources).map(CompositeValuesSourceConfig::name).collect(Collectors.toList());
|
||||||
|
this.formats = Arrays.stream(sources).map(CompositeValuesSourceConfig::format).collect(Collectors.toList());
|
||||||
// we use slot 0 to fill the current document (size+1).
|
// we use slot 0 to fill the current document (size+1).
|
||||||
this.array = new CompositeValuesComparator(context.searcher().getIndexReader(), sources, size+1);
|
this.array = new CompositeValuesComparator(context.searcher().getIndexReader(), sources, size+1);
|
||||||
if (rawAfterKey != null) {
|
if (rawAfterKey != null) {
|
||||||
|
@ -131,15 +134,17 @@ final class CompositeAggregator extends BucketsAggregator {
|
||||||
CompositeKey key = array.toCompositeKey(slot);
|
CompositeKey key = array.toCompositeKey(slot);
|
||||||
InternalAggregations aggs = bucketAggregations(slot);
|
InternalAggregations aggs = bucketAggregations(slot);
|
||||||
int docCount = bucketDocCount(slot);
|
int docCount = bucketDocCount(slot);
|
||||||
buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, docCount, aggs);
|
buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs);
|
||||||
}
|
}
|
||||||
return new InternalComposite(name, size, sourceNames, Arrays.asList(buckets), reverseMuls, pipelineAggregators(), metaData());
|
return new InternalComposite(name, size, sourceNames, formats, Arrays.asList(buckets), reverseMuls,
|
||||||
|
pipelineAggregators(), metaData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InternalAggregation buildEmptyAggregation() {
|
public InternalAggregation buildEmptyAggregation() {
|
||||||
final int[] reverseMuls = getReverseMuls();
|
final int[] reverseMuls = getReverseMuls();
|
||||||
return new InternalComposite(name, size, sourceNames, Collections.emptyList(), reverseMuls, pipelineAggregators(), metaData());
|
return new InternalComposite(name, size, sourceNames, formats, Collections.emptyList(), reverseMuls,
|
||||||
|
pipelineAggregators(), metaData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -56,7 +56,7 @@ final class CompositeValuesComparator {
|
||||||
if (vs.isFloatingPoint()) {
|
if (vs.isFloatingPoint()) {
|
||||||
arrays[i] = CompositeValuesSource.wrapDouble(vs, size, reverseMul);
|
arrays[i] = CompositeValuesSource.wrapDouble(vs, size, reverseMul);
|
||||||
} else {
|
} else {
|
||||||
arrays[i] = CompositeValuesSource.wrapLong(vs, size, reverseMul);
|
arrays[i] = CompositeValuesSource.wrapLong(vs, sources[i].format(), size, reverseMul);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,10 @@ import org.apache.lucene.index.SortedNumericDocValues;
|
||||||
import org.apache.lucene.index.SortedSetDocValues;
|
import org.apache.lucene.index.SortedSetDocValues;
|
||||||
import org.apache.lucene.search.LeafCollector;
|
import org.apache.lucene.search.LeafCollector;
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
|
||||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||||
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
|
|
||||||
|
@ -96,8 +98,9 @@ abstract class CompositeValuesSource<VS extends ValuesSource, T extends Comparab
|
||||||
/**
|
/**
|
||||||
* Creates a {@link CompositeValuesSource} that generates long values.
|
* Creates a {@link CompositeValuesSource} that generates long values.
|
||||||
*/
|
*/
|
||||||
static CompositeValuesSource<ValuesSource.Numeric, Long> wrapLong(ValuesSource.Numeric vs, int size, int reverseMul) {
|
static CompositeValuesSource<ValuesSource.Numeric, Long> wrapLong(ValuesSource.Numeric vs, DocValueFormat format,
|
||||||
return new LongValuesSource(vs, size, reverseMul);
|
int size, int reverseMul) {
|
||||||
|
return new LongValuesSource(vs, format, size, reverseMul);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -273,9 +276,12 @@ abstract class CompositeValuesSource<VS extends ValuesSource, T extends Comparab
|
||||||
*/
|
*/
|
||||||
private static class LongValuesSource extends CompositeValuesSource<ValuesSource.Numeric, Long> {
|
private static class LongValuesSource extends CompositeValuesSource<ValuesSource.Numeric, Long> {
|
||||||
private final long[] values;
|
private final long[] values;
|
||||||
|
// handles "format" for date histogram source
|
||||||
|
private final DocValueFormat format;
|
||||||
|
|
||||||
LongValuesSource(ValuesSource.Numeric vs, int size, int reverseMul) {
|
LongValuesSource(ValuesSource.Numeric vs, DocValueFormat format, int size, int reverseMul) {
|
||||||
super(vs, size, reverseMul);
|
super(vs, size, reverseMul);
|
||||||
|
this.format = format;
|
||||||
this.values = new long[size];
|
this.values = new long[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +310,11 @@ abstract class CompositeValuesSource<VS extends ValuesSource, T extends Comparab
|
||||||
if (value instanceof Number) {
|
if (value instanceof Number) {
|
||||||
topValue = ((Number) value).longValue();
|
topValue = ((Number) value).longValue();
|
||||||
} else {
|
} else {
|
||||||
topValue = Long.parseLong(value.toString());
|
// for date histogram source with "format", the after value is formatted
|
||||||
|
// as a string so we need to retrieve the original value in milliseconds.
|
||||||
|
topValue = format.parseLong(value.toString(), false, () -> {
|
||||||
|
throw new IllegalArgumentException("now() is not supported in [after] key");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext;
|
||||||
import org.apache.lucene.index.SortedNumericDocValues;
|
import org.apache.lucene.index.SortedNumericDocValues;
|
||||||
import org.apache.lucene.index.SortedSetDocValues;
|
import org.apache.lucene.index.SortedSetDocValues;
|
||||||
import org.apache.lucene.search.SortField;
|
import org.apache.lucene.search.SortField;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
@ -51,6 +52,7 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
private ValueType valueType = null;
|
private ValueType valueType = null;
|
||||||
private Object missing = null;
|
private Object missing = null;
|
||||||
private SortOrder order = SortOrder.ASC;
|
private SortOrder order = SortOrder.ASC;
|
||||||
|
private String format = null;
|
||||||
|
|
||||||
CompositeValuesSourceBuilder(String name) {
|
CompositeValuesSourceBuilder(String name) {
|
||||||
this(name, null);
|
this(name, null);
|
||||||
|
@ -72,6 +74,11 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
}
|
}
|
||||||
this.missing = in.readGenericValue();
|
this.missing = in.readGenericValue();
|
||||||
this.order = SortOrder.readFromStream(in);
|
this.order = SortOrder.readFromStream(in);
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
|
||||||
|
this.format = in.readOptionalString();
|
||||||
|
} else {
|
||||||
|
this.format = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,6 +97,9 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
}
|
}
|
||||||
out.writeGenericValue(missing);
|
out.writeGenericValue(missing);
|
||||||
order.writeTo(out);
|
order.writeTo(out);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
|
||||||
|
out.writeOptionalString(format);
|
||||||
|
}
|
||||||
innerWriteTo(out);
|
innerWriteTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +122,9 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
if (valueType != null) {
|
if (valueType != null) {
|
||||||
builder.field("value_type", valueType.getPreferredName());
|
builder.field("value_type", valueType.getPreferredName());
|
||||||
}
|
}
|
||||||
|
if (format != null) {
|
||||||
|
builder.field("format", format);
|
||||||
|
}
|
||||||
builder.field("order", order);
|
builder.field("order", order);
|
||||||
doXContentBody(builder, params);
|
doXContentBody(builder, params);
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
@ -120,7 +133,7 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int hashCode() {
|
public final int hashCode() {
|
||||||
return Objects.hash(field, missing, script, valueType, order, innerHashCode());
|
return Objects.hash(field, missing, script, valueType, order, format, innerHashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int innerHashCode();
|
protected abstract int innerHashCode();
|
||||||
|
@ -137,6 +150,7 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
Objects.equals(valueType, that.valueType()) &&
|
Objects.equals(valueType, that.valueType()) &&
|
||||||
Objects.equals(missing, that.missing()) &&
|
Objects.equals(missing, that.missing()) &&
|
||||||
Objects.equals(order, that.order()) &&
|
Objects.equals(order, that.order()) &&
|
||||||
|
Objects.equals(format, that.format()) &&
|
||||||
innerEquals(that);
|
innerEquals(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +268,24 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the format to use for the output of the aggregation.
|
||||||
|
*/
|
||||||
|
public AB format(String format) {
|
||||||
|
if (format == null) {
|
||||||
|
throw new IllegalArgumentException("[format] must not be null: [" + name + "]");
|
||||||
|
}
|
||||||
|
this.format = format;
|
||||||
|
return (AB) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the format to use for the output of the aggregation.
|
||||||
|
*/
|
||||||
|
public String format() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link CompositeValuesSourceConfig} for this source.
|
* Creates a {@link CompositeValuesSourceConfig} for this source.
|
||||||
*
|
*
|
||||||
|
@ -271,7 +303,7 @@ public abstract class CompositeValuesSourceBuilder<AB extends CompositeValuesSou
|
||||||
|
|
||||||
public final CompositeValuesSourceConfig build(SearchContext context, int pos, int numPos, SortField sortField) throws IOException {
|
public final CompositeValuesSourceConfig build(SearchContext context, int pos, int numPos, SortField sortField) throws IOException {
|
||||||
ValuesSourceConfig<?> config = ValuesSourceConfig.resolve(context.getQueryShardContext(),
|
ValuesSourceConfig<?> config = ValuesSourceConfig.resolve(context.getQueryShardContext(),
|
||||||
valueType, field, script, missing, null, null);
|
valueType, field, script, missing, null, format);
|
||||||
return innerBuild(context, config, pos, numPos, sortField);
|
return innerBuild(context, config, pos, numPos, sortField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,30 +19,47 @@
|
||||||
|
|
||||||
package org.elasticsearch.search.aggregations.bucket.composite;
|
package org.elasticsearch.search.aggregations.bucket.composite;
|
||||||
|
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
import org.elasticsearch.search.aggregations.support.ValuesSource;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
|
|
||||||
class CompositeValuesSourceConfig {
|
class CompositeValuesSourceConfig {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final ValuesSource vs;
|
private final ValuesSource vs;
|
||||||
|
private final DocValueFormat format;
|
||||||
private final int reverseMul;
|
private final int reverseMul;
|
||||||
private final boolean canEarlyTerminate;
|
private final boolean canEarlyTerminate;
|
||||||
|
|
||||||
CompositeValuesSourceConfig(String name, ValuesSource vs, SortOrder order, boolean canEarlyTerminate) {
|
CompositeValuesSourceConfig(String name, ValuesSource vs, DocValueFormat format, SortOrder order, boolean canEarlyTerminate) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.vs = vs;
|
this.vs = vs;
|
||||||
|
this.format = format;
|
||||||
this.canEarlyTerminate = canEarlyTerminate;
|
this.canEarlyTerminate = canEarlyTerminate;
|
||||||
this.reverseMul = order == SortOrder.ASC ? 1 : -1;
|
this.reverseMul = order == SortOrder.ASC ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name associated with this configuration.
|
||||||
|
*/
|
||||||
String name() {
|
String name() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ValuesSource} for this configuration.
|
||||||
|
*/
|
||||||
ValuesSource valuesSource() {
|
ValuesSource valuesSource() {
|
||||||
return vs;
|
return vs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link DocValueFormat} to use for formatting the keys.
|
||||||
|
* {@link DocValueFormat#RAW} means no formatting.
|
||||||
|
*/
|
||||||
|
DocValueFormat format() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sort order for the values source (e.g. -1 for descending and 1 for ascending).
|
* The sort order for the values source (e.g. -1 for descending and 1 for ascending).
|
||||||
*/
|
*/
|
||||||
|
@ -51,6 +68,9 @@ class CompositeValuesSourceConfig {
|
||||||
return reverseMul;
|
return reverseMul;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this {@link ValuesSource} is used to sort the index.
|
||||||
|
*/
|
||||||
boolean canEarlyTerminate() {
|
boolean canEarlyTerminate() {
|
||||||
return canEarlyTerminate;
|
return canEarlyTerminate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.script.Script;
|
import org.elasticsearch.script.Script;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
|
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
||||||
import org.elasticsearch.search.aggregations.support.FieldContext;
|
import org.elasticsearch.search.aggregations.support.FieldContext;
|
||||||
|
@ -46,8 +48,8 @@ import java.util.Objects;
|
||||||
import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder.DATE_FIELD_UNITS;
|
import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder.DATE_FIELD_UNITS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link CompositeValuesSourceBuilder} that that builds a {@link RoundingValuesSource} from a {@link Script} or
|
* A {@link CompositeValuesSourceBuilder} that builds a {@link RoundingValuesSource} from a {@link Script} or
|
||||||
* a field name.
|
* a field name using the provided interval.
|
||||||
*/
|
*/
|
||||||
public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuilder<DateHistogramValuesSourceBuilder> {
|
public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuilder<DateHistogramValuesSourceBuilder> {
|
||||||
static final String TYPE = "date_histogram";
|
static final String TYPE = "date_histogram";
|
||||||
|
@ -55,6 +57,7 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild
|
||||||
private static final ObjectParser<DateHistogramValuesSourceBuilder, Void> PARSER;
|
private static final ObjectParser<DateHistogramValuesSourceBuilder, Void> PARSER;
|
||||||
static {
|
static {
|
||||||
PARSER = new ObjectParser<>(DateHistogramValuesSourceBuilder.TYPE);
|
PARSER = new ObjectParser<>(DateHistogramValuesSourceBuilder.TYPE);
|
||||||
|
PARSER.declareString(DateHistogramValuesSourceBuilder::format, new ParseField("format"));
|
||||||
PARSER.declareField((histogram, interval) -> {
|
PARSER.declareField((histogram, interval) -> {
|
||||||
if (interval instanceof Long) {
|
if (interval instanceof Long) {
|
||||||
histogram.interval((long) interval);
|
histogram.interval((long) interval);
|
||||||
|
@ -235,7 +238,11 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild
|
||||||
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
||||||
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
||||||
}
|
}
|
||||||
return new CompositeValuesSourceConfig(name, vs, order(), canEarlyTerminate);
|
// dates are returned as timestamp in milliseconds-since-the-epoch unless a specific date format
|
||||||
|
// is specified in the builder.
|
||||||
|
final DocValueFormat docValueFormat = format() == null ? DocValueFormat.RAW : config.format();
|
||||||
|
return new CompositeValuesSourceConfig(name, vs, docValueFormat,
|
||||||
|
order(), canEarlyTerminate);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName());
|
throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link CompositeValuesSourceBuilder} that that builds a {@link HistogramValuesSource} from another numeric values source
|
* A {@link CompositeValuesSourceBuilder} that builds a {@link HistogramValuesSource} from another numeric values source
|
||||||
* using the provided interval.
|
* using the provided interval.
|
||||||
*/
|
*/
|
||||||
public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder<HistogramValuesSourceBuilder> {
|
public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder<HistogramValuesSourceBuilder> {
|
||||||
|
@ -128,7 +128,7 @@ public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder<H
|
||||||
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
||||||
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
||||||
}
|
}
|
||||||
return new CompositeValuesSourceConfig(name, vs, order(), canEarlyTerminate);
|
return new CompositeValuesSourceConfig(name, vs, config.format(), order(), canEarlyTerminate);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName());
|
throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
package org.elasticsearch.search.aggregations.bucket.composite;
|
package org.elasticsearch.search.aggregations.bucket.composite;
|
||||||
|
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.Aggregations;
|
import org.elasticsearch.search.aggregations.Aggregations;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregations;
|
import org.elasticsearch.search.aggregations.InternalAggregations;
|
||||||
|
@ -35,6 +37,7 @@ import java.util.AbstractMap;
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -49,11 +52,14 @@ public class InternalComposite
|
||||||
private final List<InternalBucket> buckets;
|
private final List<InternalBucket> buckets;
|
||||||
private final int[] reverseMuls;
|
private final int[] reverseMuls;
|
||||||
private final List<String> sourceNames;
|
private final List<String> sourceNames;
|
||||||
|
private final List<DocValueFormat> formats;
|
||||||
|
|
||||||
InternalComposite(String name, int size, List<String> sourceNames, List<InternalBucket> buckets, int[] reverseMuls,
|
InternalComposite(String name, int size, List<String> sourceNames, List<DocValueFormat> formats,
|
||||||
|
List<InternalBucket> buckets, int[] reverseMuls,
|
||||||
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
|
List<PipelineAggregator> pipelineAggregators, Map<String, Object> metaData) {
|
||||||
super(name, pipelineAggregators, metaData);
|
super(name, pipelineAggregators, metaData);
|
||||||
this.sourceNames = sourceNames;
|
this.sourceNames = sourceNames;
|
||||||
|
this.formats = formats;
|
||||||
this.buckets = buckets;
|
this.buckets = buckets;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.reverseMuls = reverseMuls;
|
this.reverseMuls = reverseMuls;
|
||||||
|
@ -63,14 +69,27 @@ public class InternalComposite
|
||||||
super(in);
|
super(in);
|
||||||
this.size = in.readVInt();
|
this.size = in.readVInt();
|
||||||
this.sourceNames = in.readList(StreamInput::readString);
|
this.sourceNames = in.readList(StreamInput::readString);
|
||||||
|
this.formats = new ArrayList<>(sourceNames.size());
|
||||||
|
for (int i = 0; i < sourceNames.size(); i++) {
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
|
||||||
|
formats.add(in.readNamedWriteable(DocValueFormat.class));
|
||||||
|
} else {
|
||||||
|
formats.add(DocValueFormat.RAW);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.reverseMuls = in.readIntArray();
|
this.reverseMuls = in.readIntArray();
|
||||||
this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, reverseMuls));
|
this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, formats, reverseMuls));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doWriteTo(StreamOutput out) throws IOException {
|
protected void doWriteTo(StreamOutput out) throws IOException {
|
||||||
out.writeVInt(size);
|
out.writeVInt(size);
|
||||||
out.writeStringList(sourceNames);
|
out.writeStringList(sourceNames);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
|
||||||
|
for (DocValueFormat format : formats) {
|
||||||
|
out.writeNamedWriteable(format);
|
||||||
|
}
|
||||||
|
}
|
||||||
out.writeIntArray(reverseMuls);
|
out.writeIntArray(reverseMuls);
|
||||||
out.writeList(buckets);
|
out.writeList(buckets);
|
||||||
}
|
}
|
||||||
|
@ -87,12 +106,13 @@ public class InternalComposite
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InternalComposite create(List<InternalBucket> buckets) {
|
public InternalComposite create(List<InternalBucket> buckets) {
|
||||||
return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, pipelineAggregators(), getMetaData());
|
return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, pipelineAggregators(), getMetaData());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InternalBucket createBucket(InternalAggregations aggregations, InternalBucket prototype) {
|
public InternalBucket createBucket(InternalAggregations aggregations, InternalBucket prototype) {
|
||||||
return new InternalBucket(prototype.sourceNames, prototype.key, prototype.reverseMuls, prototype.docCount, aggregations);
|
return new InternalBucket(prototype.sourceNames, prototype.formats, prototype.key, prototype.reverseMuls,
|
||||||
|
prototype.docCount, aggregations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
|
@ -149,7 +169,7 @@ public class InternalComposite
|
||||||
reduceContext.consumeBucketsAndMaybeBreak(1);
|
reduceContext.consumeBucketsAndMaybeBreak(1);
|
||||||
result.add(reduceBucket);
|
result.add(reduceBucket);
|
||||||
}
|
}
|
||||||
return new InternalComposite(name, size, sourceNames, result, reverseMuls, pipelineAggregators(), metaData);
|
return new InternalComposite(name, size, sourceNames, formats, result, reverseMuls, pipelineAggregators(), metaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -191,18 +211,21 @@ public class InternalComposite
|
||||||
private final InternalAggregations aggregations;
|
private final InternalAggregations aggregations;
|
||||||
private final transient int[] reverseMuls;
|
private final transient int[] reverseMuls;
|
||||||
private final transient List<String> sourceNames;
|
private final transient List<String> sourceNames;
|
||||||
|
private final transient List<DocValueFormat> formats;
|
||||||
|
|
||||||
|
|
||||||
InternalBucket(List<String> sourceNames, CompositeKey key, int[] reverseMuls, long docCount, InternalAggregations aggregations) {
|
InternalBucket(List<String> sourceNames, List<DocValueFormat> formats, CompositeKey key, int[] reverseMuls, long docCount,
|
||||||
|
InternalAggregations aggregations) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.docCount = docCount;
|
this.docCount = docCount;
|
||||||
this.aggregations = aggregations;
|
this.aggregations = aggregations;
|
||||||
this.reverseMuls = reverseMuls;
|
this.reverseMuls = reverseMuls;
|
||||||
this.sourceNames = sourceNames;
|
this.sourceNames = sourceNames;
|
||||||
|
this.formats = formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
InternalBucket(StreamInput in, List<String> sourceNames, int[] reverseMuls) throws IOException {
|
InternalBucket(StreamInput in, List<String> sourceNames, List<DocValueFormat> formats, int[] reverseMuls) throws IOException {
|
||||||
final Comparable<?>[] values = new Comparable<?>[in.readVInt()];
|
final Comparable<?>[] values = new Comparable<?>[in.readVInt()];
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
values[i] = (Comparable<?>) in.readGenericValue();
|
values[i] = (Comparable<?>) in.readGenericValue();
|
||||||
|
@ -212,6 +235,7 @@ public class InternalComposite
|
||||||
this.aggregations = InternalAggregations.readAggregations(in);
|
this.aggregations = InternalAggregations.readAggregations(in);
|
||||||
this.reverseMuls = reverseMuls;
|
this.reverseMuls = reverseMuls;
|
||||||
this.sourceNames = sourceNames;
|
this.sourceNames = sourceNames;
|
||||||
|
this.formats = formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -242,9 +266,11 @@ public class InternalComposite
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getKey() {
|
public Map<String, Object> getKey() {
|
||||||
return new ArrayMap(sourceNames, key.values());
|
// returns the formatted key in a map
|
||||||
|
return new ArrayMap(sourceNames, formats, key.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the raw key (without formatting to preserve the natural order).
|
||||||
// visible for testing
|
// visible for testing
|
||||||
CompositeKey getRawKey() {
|
CompositeKey getRawKey() {
|
||||||
return key;
|
return key;
|
||||||
|
@ -260,7 +286,7 @@ public class InternalComposite
|
||||||
}
|
}
|
||||||
builder.append(sourceNames.get(i));
|
builder.append(sourceNames.get(i));
|
||||||
builder.append('=');
|
builder.append('=');
|
||||||
builder.append(formatObject(key.get(i)));
|
builder.append(formatObject(key.get(i), formats.get(i)));
|
||||||
}
|
}
|
||||||
builder.append('}');
|
builder.append('}');
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@ -284,7 +310,7 @@ public class InternalComposite
|
||||||
aggregations.add(bucket.aggregations);
|
aggregations.add(bucket.aggregations);
|
||||||
}
|
}
|
||||||
InternalAggregations aggs = InternalAggregations.reduce(aggregations, reduceContext);
|
InternalAggregations aggs = InternalAggregations.reduce(aggregations, reduceContext);
|
||||||
return new InternalBucket(sourceNames, key, reverseMuls, docCount, aggs);
|
return new InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -303,26 +329,52 @@ public class InternalComposite
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
/**
|
/**
|
||||||
* See {@link CompositeAggregation#bucketToXContentFragment}
|
* See {@link CompositeAggregation#bucketToXContent}
|
||||||
*/
|
*/
|
||||||
throw new UnsupportedOperationException("not implemented");
|
throw new UnsupportedOperationException("not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object formatObject(Object obj) {
|
/**
|
||||||
if (obj instanceof BytesRef) {
|
* Format <code>obj</code> using the provided {@link DocValueFormat}.
|
||||||
return ((BytesRef) obj).utf8ToString();
|
* If the format is equals to {@link DocValueFormat#RAW}, the object is returned as is
|
||||||
|
* for numbers and a string for {@link BytesRef}s.
|
||||||
|
*/
|
||||||
|
static Object formatObject(Object obj, DocValueFormat format) {
|
||||||
|
if (obj.getClass() == BytesRef.class) {
|
||||||
|
BytesRef value = (BytesRef) obj;
|
||||||
|
if (format == DocValueFormat.RAW) {
|
||||||
|
return value.utf8ToString();
|
||||||
|
} else {
|
||||||
|
return format.format((BytesRef) obj);
|
||||||
|
}
|
||||||
|
} else if (obj.getClass() == Long.class) {
|
||||||
|
Long value = (Long) obj;
|
||||||
|
if (format == DocValueFormat.RAW) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return format.format(value);
|
||||||
|
}
|
||||||
|
} else if (obj.getClass() == Double.class) {
|
||||||
|
Double value = (Double) obj;
|
||||||
|
if (format == DocValueFormat.RAW) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return format.format((Double) obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ArrayMap extends AbstractMap<String, Object> {
|
private static class ArrayMap extends AbstractMap<String, Object> {
|
||||||
final List<String> keys;
|
final List<String> keys;
|
||||||
|
final List<DocValueFormat> formats;
|
||||||
final Object[] values;
|
final Object[] values;
|
||||||
|
|
||||||
ArrayMap(List<String> keys, Object[] values) {
|
ArrayMap(List<String> keys, List<DocValueFormat> formats, Object[] values) {
|
||||||
assert keys.size() == values.length;
|
assert keys.size() == values.length && keys.size() == formats.size();
|
||||||
this.keys = keys;
|
this.keys = keys;
|
||||||
|
this.formats = formats;
|
||||||
this.values = values;
|
this.values = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +387,7 @@ public class InternalComposite
|
||||||
public Object get(Object key) {
|
public Object get(Object key) {
|
||||||
for (int i = 0; i < keys.size(); i++) {
|
for (int i = 0; i < keys.size(); i++) {
|
||||||
if (key.equals(keys.get(i))) {
|
if (key.equals(keys.get(i))) {
|
||||||
return formatObject(values[i]);
|
return formatObject(values[i], formats.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -356,7 +408,7 @@ public class InternalComposite
|
||||||
@Override
|
@Override
|
||||||
public Entry<String, Object> next() {
|
public Entry<String, Object> next() {
|
||||||
SimpleEntry<String, Object> entry =
|
SimpleEntry<String, Object> entry =
|
||||||
new SimpleEntry<>(keys.get(pos), formatObject(values[pos]));
|
new SimpleEntry<>(keys.get(pos), formatObject(values[pos], formats.get(pos)));
|
||||||
++ pos;
|
++ pos;
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,6 @@ public class TermsValuesSourceBuilder extends CompositeValuesSourceBuilder<Terms
|
||||||
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(),
|
||||||
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField);
|
||||||
}
|
}
|
||||||
return new CompositeValuesSourceConfig(name, vs, order(), canEarlyTerminate);
|
return new CompositeValuesSourceConfig(name, vs, config.format(), order(), canEarlyTerminate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.lucene.util.BytesRef;
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.apache.lucene.util.NumericUtils;
|
import org.apache.lucene.util.NumericUtils;
|
||||||
import org.apache.lucene.util.TestUtil;
|
import org.apache.lucene.util.TestUtil;
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.index.Index;
|
import org.elasticsearch.index.Index;
|
||||||
import org.elasticsearch.index.IndexSettings;
|
import org.elasticsearch.index.IndexSettings;
|
||||||
|
@ -68,6 +69,9 @@ import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
|
|
||||||
public class CompositeAggregatorTests extends AggregatorTestCase {
|
public class CompositeAggregatorTests extends AggregatorTestCase {
|
||||||
private static MappedFieldType[] FIELD_TYPES;
|
private static MappedFieldType[] FIELD_TYPES;
|
||||||
|
|
||||||
|
@ -761,6 +765,89 @@ public class CompositeAggregatorTests extends AggregatorTestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testWithDateHistogramAndFormat() throws IOException {
|
||||||
|
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
|
||||||
|
dataset.addAll(
|
||||||
|
Arrays.asList(
|
||||||
|
createDocument("date", asLong("2017-10-20T03:08:45")),
|
||||||
|
createDocument("date", asLong("2016-09-20T09:00:34")),
|
||||||
|
createDocument("date", asLong("2016-09-20T11:34:00")),
|
||||||
|
createDocument("date", asLong("2017-10-20T06:09:24")),
|
||||||
|
createDocument("date", asLong("2017-10-19T06:09:24")),
|
||||||
|
createDocument("long", 4L)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
final Sort sort = new Sort(new SortedNumericSortField("date", SortField.Type.LONG));
|
||||||
|
testSearchCase(new MatchAllDocsQuery(), sort, dataset,
|
||||||
|
() -> {
|
||||||
|
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
|
||||||
|
.field("date")
|
||||||
|
.dateHistogramInterval(DateHistogramInterval.days(1))
|
||||||
|
.format("yyyy-MM-dd");
|
||||||
|
return new CompositeAggregationBuilder("name", Collections.singletonList(histo));
|
||||||
|
},
|
||||||
|
(result) -> {
|
||||||
|
assertEquals(3, result.getBuckets().size());
|
||||||
|
assertEquals("{date=2016-09-20}", result.getBuckets().get(0).getKeyAsString());
|
||||||
|
assertEquals(2L, result.getBuckets().get(0).getDocCount());
|
||||||
|
assertEquals("{date=2017-10-19}", result.getBuckets().get(1).getKeyAsString());
|
||||||
|
assertEquals(1L, result.getBuckets().get(1).getDocCount());
|
||||||
|
assertEquals("{date=2017-10-20}", result.getBuckets().get(2).getKeyAsString());
|
||||||
|
assertEquals(2L, result.getBuckets().get(2).getDocCount());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
testSearchCase(new MatchAllDocsQuery(), sort, dataset,
|
||||||
|
() -> {
|
||||||
|
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
|
||||||
|
.field("date")
|
||||||
|
.dateHistogramInterval(DateHistogramInterval.days(1))
|
||||||
|
.format("yyyy-MM-dd");
|
||||||
|
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
|
||||||
|
.aggregateAfter(createAfterKey("date", "2016-09-20"));
|
||||||
|
|
||||||
|
}, (result) -> {
|
||||||
|
assertEquals(2, result.getBuckets().size());
|
||||||
|
assertEquals("{date=2017-10-19}", result.getBuckets().get(0).getKeyAsString());
|
||||||
|
assertEquals(1L, result.getBuckets().get(0).getDocCount());
|
||||||
|
assertEquals("{date=2017-10-20}", result.getBuckets().get(1).getKeyAsString());
|
||||||
|
assertEquals(2L, result.getBuckets().get(1).getDocCount());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testThatDateHistogramFailsFormatAfter() throws IOException {
|
||||||
|
ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class,
|
||||||
|
() -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(),
|
||||||
|
() -> {
|
||||||
|
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
|
||||||
|
.field("date")
|
||||||
|
.dateHistogramInterval(DateHistogramInterval.days(1))
|
||||||
|
.format("yyyy-MM-dd");
|
||||||
|
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
|
||||||
|
.aggregateAfter(createAfterKey("date", "now"));
|
||||||
|
},
|
||||||
|
(result) -> {}
|
||||||
|
));
|
||||||
|
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
|
||||||
|
assertThat(exc.getCause().getMessage(), containsString("now() is not supported in [after] key"));
|
||||||
|
|
||||||
|
exc = expectThrows(ElasticsearchParseException.class,
|
||||||
|
() -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(),
|
||||||
|
() -> {
|
||||||
|
DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date")
|
||||||
|
.field("date")
|
||||||
|
.dateHistogramInterval(DateHistogramInterval.days(1))
|
||||||
|
.format("yyyy-MM-dd");
|
||||||
|
return new CompositeAggregationBuilder("name", Collections.singletonList(histo))
|
||||||
|
.aggregateAfter(createAfterKey("date", "1474329600000"));
|
||||||
|
},
|
||||||
|
(result) -> {}
|
||||||
|
));
|
||||||
|
assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class));
|
||||||
|
assertThat(exc.getCause().getMessage(), containsString("Parse failure"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testWithDateHistogramAndTimeZone() throws IOException {
|
public void testWithDateHistogramAndTimeZone() throws IOException {
|
||||||
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
|
final List<Map<String, List<Object>>> dataset = new ArrayList<>();
|
||||||
dataset.addAll(
|
dataset.addAll(
|
||||||
|
|
|
@ -21,12 +21,15 @@ package org.elasticsearch.search.aggregations.bucket.composite;
|
||||||
|
|
||||||
import org.apache.lucene.util.BytesRef;
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
import org.elasticsearch.common.joda.Joda;
|
||||||
import org.elasticsearch.common.util.BigArrays;
|
import org.elasticsearch.common.util.BigArrays;
|
||||||
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregations;
|
import org.elasticsearch.search.aggregations.InternalAggregations;
|
||||||
import org.elasticsearch.search.aggregations.ParsedAggregation;
|
import org.elasticsearch.search.aggregations.ParsedAggregation;
|
||||||
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
|
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
|
||||||
import org.elasticsearch.test.InternalMultiBucketAggregationTestCase;
|
import org.elasticsearch.test.InternalMultiBucketAggregationTestCase;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -41,28 +44,45 @@ import java.util.TreeSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLengthBetween;
|
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLengthBetween;
|
||||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomLongBetween;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
|
|
||||||
public class InternalCompositeTests extends InternalMultiBucketAggregationTestCase<InternalComposite> {
|
public class InternalCompositeTests extends InternalMultiBucketAggregationTestCase<InternalComposite> {
|
||||||
private List<String> sourceNames;
|
private List<String> sourceNames;
|
||||||
|
private List<DocValueFormat> formats;
|
||||||
private int[] reverseMuls;
|
private int[] reverseMuls;
|
||||||
private int[] formats;
|
private int[] types;
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
|
private static DocValueFormat randomDocValueFormat(boolean isLong) {
|
||||||
|
if (isLong) {
|
||||||
|
// we use specific format only for date histogram on a long/date field
|
||||||
|
if (randomBoolean()) {
|
||||||
|
return new DocValueFormat.DateTime(Joda.forPattern("epoch_second"), DateTimeZone.forOffsetHours(1));
|
||||||
|
} else {
|
||||||
|
return DocValueFormat.RAW;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// and the raw format for the other types
|
||||||
|
return DocValueFormat.RAW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
int numFields = randomIntBetween(1, 10);
|
int numFields = randomIntBetween(1, 10);
|
||||||
size = randomNumberOfBuckets();
|
size = randomNumberOfBuckets();
|
||||||
sourceNames = new ArrayList<>();
|
sourceNames = new ArrayList<>();
|
||||||
|
formats = new ArrayList<>();
|
||||||
reverseMuls = new int[numFields];
|
reverseMuls = new int[numFields];
|
||||||
formats = new int[numFields];
|
types = new int[numFields];
|
||||||
for (int i = 0; i < numFields; i++) {
|
for (int i = 0; i < numFields; i++) {
|
||||||
sourceNames.add("field_" + i);
|
sourceNames.add("field_" + i);
|
||||||
reverseMuls[i] = randomBoolean() ? 1 : -1;
|
reverseMuls[i] = randomBoolean() ? 1 : -1;
|
||||||
formats[i] = randomIntBetween(0, 2);
|
int type = randomIntBetween(0, 2);
|
||||||
|
types[i] = type;
|
||||||
|
formats.add(randomDocValueFormat(type == 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,9 +90,10 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
sourceNames= null;
|
sourceNames = null;
|
||||||
reverseMuls = null;
|
|
||||||
formats = null;
|
formats = null;
|
||||||
|
reverseMuls = null;
|
||||||
|
types = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -93,7 +114,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
private CompositeKey createCompositeKey() {
|
private CompositeKey createCompositeKey() {
|
||||||
Comparable<?>[] keys = new Comparable<?>[sourceNames.size()];
|
Comparable<?>[] keys = new Comparable<?>[sourceNames.size()];
|
||||||
for (int j = 0; j < keys.length; j++) {
|
for (int j = 0; j < keys.length; j++) {
|
||||||
switch (formats[j]) {
|
switch (types[j]) {
|
||||||
case 0:
|
case 0:
|
||||||
keys[j] = randomLong();
|
keys[j] = randomLong();
|
||||||
break;
|
break;
|
||||||
|
@ -123,19 +144,6 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Comparator<InternalComposite.InternalBucket> getBucketComparator() {
|
|
||||||
return (o1, o2) -> {
|
|
||||||
for (int i = 0; i < o1.getRawKey().size(); i++) {
|
|
||||||
int cmp = ((Comparable) o1.getRawKey().get(i)).compareTo(o2.getRawKey().get(i)) * reverseMuls[i];
|
|
||||||
if (cmp != 0) {
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InternalComposite createTestInstance(String name, List<PipelineAggregator> pipelineAggregators,
|
protected InternalComposite createTestInstance(String name, List<PipelineAggregator> pipelineAggregators,
|
||||||
Map<String, Object> metaData, InternalAggregations aggregations) {
|
Map<String, Object> metaData, InternalAggregations aggregations) {
|
||||||
|
@ -149,11 +157,11 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
}
|
}
|
||||||
keys.add(key);
|
keys.add(key);
|
||||||
InternalComposite.InternalBucket bucket =
|
InternalComposite.InternalBucket bucket =
|
||||||
new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, 1L, aggregations);
|
new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, 1L, aggregations);
|
||||||
buckets.add(bucket);
|
buckets.add(bucket);
|
||||||
}
|
}
|
||||||
Collections.sort(buckets, (o1, o2) -> o1.compareKey(o2));
|
Collections.sort(buckets, (o1, o2) -> o1.compareKey(o2));
|
||||||
return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, Collections.emptyList(), metaData);
|
return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, Collections.emptyList(), metaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -172,7 +180,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
buckets = new ArrayList<>(buckets);
|
buckets = new ArrayList<>(buckets);
|
||||||
buckets.add(new InternalComposite.InternalBucket(sourceNames, createCompositeKey(), reverseMuls,
|
buckets.add(new InternalComposite.InternalBucket(sourceNames, formats, createCompositeKey(), reverseMuls,
|
||||||
randomLongBetween(1, 100), InternalAggregations.EMPTY)
|
randomLongBetween(1, 100), InternalAggregations.EMPTY)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
@ -187,7 +195,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa
|
||||||
default:
|
default:
|
||||||
throw new AssertionError("illegal branch");
|
throw new AssertionError("illegal branch");
|
||||||
}
|
}
|
||||||
return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, buckets, reverseMuls,
|
return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, formats, buckets, reverseMuls,
|
||||||
instance.pipelineAggregators(), metaData);
|
instance.pipelineAggregators(), metaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue