Skip to content

Commit 6d70ccd

Browse files
committed
Refactor to leverage BucketedSort
these changes include usage of BucketedSort and ability to order the lines by both ascending and descending time/sort order.
1 parent 8afb5f6 commit 6d70ccd

File tree

14 files changed

+476
-212
lines changed

14 files changed

+476
-212
lines changed

server/src/main/java/org/elasticsearch/search/aggregations/support/MultiValuesSource.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.lucene.index.LeafReaderContext;
2222
import org.elasticsearch.index.fielddata.MultiGeoPointValues;
2323
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
24+
import org.elasticsearch.index.query.QueryShardContext;
2425
import org.elasticsearch.search.aggregations.AggregationExecutionException;
2526

2627
import java.io.IOException;

server/src/main/java/org/elasticsearch/search/sort/BucketedSort.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
* worst case. Critically, it is a very fast {@code O(1)} to check if a value
6767
* is competitive at all which, so long as buckets aren't hit in reverse
6868
* order, they mostly won't be. Extracting results in sorted order is still
69-
* {@code O(n * log n)}.
69+
* {@code O(n * log n)}.
7070
* </p>
7171
* <p>
7272
* When we first collect a bucket we make sure that we've allocated enough
@@ -90,7 +90,7 @@ public interface ExtraData {
9090
* <p>
9191
* Both parameters will have previously been loaded by
9292
* {@link Loader#loadFromDoc(long, int)} so the implementer shouldn't
93-
* need to grow the underlying storage to implement this.
93+
* need to grow the underlying storage to implement this.
9494
* </p>
9595
*/
9696
void swap(long lhs, long rhs);
@@ -128,7 +128,7 @@ public Loader loader(LeafReaderContext ctx) throws IOException {
128128
private final SortOrder order;
129129
private final DocValueFormat format;
130130
private final int bucketSize;
131-
private final ExtraData extra;
131+
protected final ExtraData extra;
132132
/**
133133
* {@code true} if the bucket is in heap mode, {@code false} if
134134
* it is still gathering.
@@ -206,9 +206,9 @@ public final List<SortValue> getValues(long bucket) {
206206
}
207207

208208
/**
209-
* Is this bucket a min heap {@code true} or in gathering mode {@code false}?
209+
* Is this bucket a min heap {@code true} or in gathering mode {@code false}?
210210
*/
211-
private boolean inHeapMode(long bucket) {
211+
public boolean inHeapMode(long bucket) {
212212
return heapMode.get(bucket);
213213
}
214214

@@ -254,7 +254,7 @@ private boolean inHeapMode(long bucket) {
254254
/**
255255
* {@code true} if the entry at index {@code lhs} is "better" than
256256
* the entry at {@code rhs}. "Better" in this means "lower" for
257-
* {@link SortOrder#ASC} and "higher" for {@link SortOrder#DESC}.
257+
* {@link SortOrder#ASC} and "higher" for {@link SortOrder#DESC}.
258258
*/
259259
protected abstract boolean betterThan(long lhs, long rhs);
260260

@@ -283,7 +283,7 @@ protected final String debugFormat() {
283283

284284
/**
285285
* Initialize the gather offsets after setting up values. Subclasses
286-
* should call this once, after setting up their {@link #values()}.
286+
* should call this once, after setting up their {@link #values()}.
287287
*/
288288
protected final void initGatherOffsets() {
289289
setNextGatherOffsets(0);
@@ -325,12 +325,12 @@ private void setNextGatherOffsets(long startingAt) {
325325
* case.
326326
* </p>
327327
* <ul>
328-
* <li>Hayward, Ryan; McDiarmid, Colin (1991).
328+
* <li>Hayward, Ryan; McDiarmid, Colin (1991).
329329
* <a href="https://web.archive.org/web/20160205023201/http://www.stats.ox.ac.uk/__data/assets/pdf_file/0015/4173/heapbuildjalg.pdf">
330330
* Average Case Analysis of Heap Building byRepeated Insertion</a> J. Algorithms.
331331
* <li>D.E. Knuth, ”The Art of Computer Programming, Vol. 3, Sorting and Searching”</li>
332332
* </ul>
333-
* @param rootIndex the index the start of the bucket
333+
* @param rootIndex the index the start of the bucket
334334
*/
335335
private void heapify(long rootIndex) {
336336
int maxParent = bucketSize / 2 - 1;
@@ -344,7 +344,7 @@ private void heapify(long rootIndex) {
344344
* runs in {@code O(log n)} time.
345345
* @param rootIndex index of the start of the bucket
346346
* @param parent Index within the bucket of the parent to check.
347-
* For example, 0 is the "root".
347+
* For example, 0 is the "root".
348348
*/
349349
private void downHeap(long rootIndex, int parent) {
350350
while (true) {
@@ -443,7 +443,7 @@ public final void collect(int doc, long bucket) throws IOException {
443443
/**
444444
* {@code true} if the sort value for the doc is "better" than the
445445
* entry at {@code index}. "Better" in means is "lower" for
446-
* {@link SortOrder#ASC} and "higher" for {@link SortOrder#DESC}.
446+
* {@link SortOrder#ASC} and "higher" for {@link SortOrder#DESC}.
447447
*/
448448
protected abstract boolean docBetterThan(long index);
449449

@@ -545,7 +545,7 @@ public abstract static class ForFloats extends BucketedSort {
545545
* The maximum size of buckets this can store. This is because we
546546
* store the next offset to write to in a float and floats only have
547547
* {@code 23} bits of mantissa so they can't accurate store values
548-
* higher than {@code 2 ^ 24}.
548+
* higher than {@code 2 ^ 24}.
549549
*/
550550
public static final int MAX_BUCKET_SIZE = (int) Math.pow(2, 24);
551551

server/src/test/java/org/elasticsearch/search/sort/BucketedSortTestCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ public void testTwoHitsDesc() throws IOException {
212212
assertThat(sort.getValues(0, extra.valueBuilder()), contains(extraValue(3000, 3), extraValue(200, 2)));
213213
}
214214
}
215-
215+
216216
public void testTwoHitsAsc() throws IOException {
217217
try (T sort = build(SortOrder.ASC, 2, new double[] {1, 2, 3})) {
218218
BucketedSort.Leaf leaf = sort.forLeaf(null);

x-pack/plugin/analytics/src/main/java/org/elasticsearch/xpack/analytics/topmetrics/TopMetricsAggregator.java

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.search.sort.BucketedSort;
2929
import org.elasticsearch.search.sort.SortBuilder;
3030
import org.elasticsearch.search.sort.SortValue;
31+
import org.elasticsearch.xpack.core.common.search.aggregations.MissingHelper;
3132
import org.elasticsearch.xpack.analytics.topmetrics.InternalTopMetrics.MetricValue;
3233

3334
import java.io.IOException;
@@ -427,62 +428,4 @@ public Loader loader(LeafReaderContext ctx) throws IOException {
427428
public void close() {}
428429
}
429430

430-
/**
431-
* Helps {@link LongMetricValues} track "empty" slots. It attempts to have
432-
* very low CPU overhead and no memory overhead when there *aren't* empty
433-
* values.
434-
*/
435-
private static class MissingHelper implements Releasable {
436-
private final BigArrays bigArrays;
437-
private BitArray tracker;
438-
439-
MissingHelper(BigArrays bigArrays) {
440-
this.bigArrays = bigArrays;
441-
}
442-
443-
void markMissing(long index) {
444-
if (tracker == null) {
445-
tracker = new BitArray(index, bigArrays);
446-
}
447-
tracker.set(index);
448-
}
449-
450-
void markNotMissing(long index) {
451-
if (tracker == null) {
452-
return;
453-
}
454-
tracker.clear(index);
455-
}
456-
457-
void swap(long lhs, long rhs) {
458-
if (tracker == null) {
459-
return;
460-
}
461-
boolean backup = tracker.get(lhs);
462-
if (tracker.get(rhs)) {
463-
tracker.set(lhs);
464-
} else {
465-
tracker.clear(lhs);
466-
}
467-
if (backup) {
468-
tracker.set(rhs);
469-
} else {
470-
tracker.clear(rhs);
471-
}
472-
}
473-
474-
boolean isEmpty(long index) {
475-
if (tracker == null) {
476-
return false;
477-
}
478-
return tracker.get(index);
479-
}
480-
481-
@Override
482-
public void close() {
483-
if (tracker != null) {
484-
tracker.close();
485-
}
486-
}
487-
}
488431
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.common.search.aggregations;
8+
9+
import org.elasticsearch.common.lease.Releasable;
10+
import org.elasticsearch.common.util.BigArrays;
11+
import org.elasticsearch.common.util.BitArray;
12+
13+
/**
14+
* Helps long-valued {@link org.elasticsearch.search.sort.BucketedSort.ExtraData} track "empty" slots. It attempts to have
15+
* very low CPU overhead and no memory overhead when there *aren't* empty
16+
* values.
17+
*/
18+
public class MissingHelper implements Releasable {
19+
private final BigArrays bigArrays;
20+
private BitArray tracker;
21+
22+
public MissingHelper(BigArrays bigArrays) {
23+
this.bigArrays = bigArrays;
24+
}
25+
26+
public void markMissing(long index) {
27+
if (tracker == null) {
28+
tracker = new BitArray(index, bigArrays);
29+
}
30+
tracker.set(index);
31+
}
32+
33+
public void markNotMissing(long index) {
34+
if (tracker == null) {
35+
return;
36+
}
37+
tracker.clear(index);
38+
}
39+
40+
public void swap(long lhs, long rhs) {
41+
if (tracker == null) {
42+
return;
43+
}
44+
boolean backup = tracker.get(lhs);
45+
if (tracker.get(rhs)) {
46+
tracker.set(lhs);
47+
} else {
48+
tracker.clear(lhs);
49+
}
50+
if (backup) {
51+
tracker.set(rhs);
52+
} else {
53+
tracker.clear(rhs);
54+
}
55+
}
56+
57+
public boolean isEmpty(long index) {
58+
if (tracker == null) {
59+
return false;
60+
}
61+
return tracker.get(index);
62+
}
63+
64+
@Override
65+
public void close() {
66+
if (tracker != null) {
67+
tracker.close();
68+
}
69+
}
70+
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/spatial/action/SpatialStatsAction.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,15 @@ public EnumCounters<Item> getStats() {
116116
@Override
117117
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
118118
EnumCounters<Item> stats = getStats();
119-
builder.startObject("stats");
120-
for (Item item : Item.values()) {
121-
builder.field(item.name().toLowerCase(Locale.ROOT) + "_usage", stats.get(item));
119+
builder.startObject();
120+
{
121+
builder.startObject("stats");
122+
{
123+
for (Item item : Item.values()) {
124+
builder.field(item.name().toLowerCase(Locale.ROOT) + "_usage", stats.get(item));
125+
}
126+
}
127+
builder.endObject();
122128
}
123129
builder.endObject();
124130
return builder;

x-pack/plugin/spatial/src/main/java/org/elasticsearch/xpack/spatial/search/aggregations/GeoLineAggregationBuilder.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
import org.elasticsearch.common.xcontent.ToXContent;
1313
import org.elasticsearch.common.xcontent.XContentBuilder;
1414
import org.elasticsearch.index.query.QueryBuilder;
15-
import org.elasticsearch.index.query.QueryShardContext;
1615
import org.elasticsearch.search.DocValueFormat;
1716
import org.elasticsearch.search.aggregations.AggregationBuilder;
1817
import org.elasticsearch.search.aggregations.AggregatorFactories;
1918
import org.elasticsearch.search.aggregations.AggregatorFactory;
19+
import org.elasticsearch.search.aggregations.support.AggregationContext;
2020
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
2121
import org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregationBuilder;
2222
import org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregatorFactory;
@@ -26,6 +26,7 @@
2626
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
2727
import org.elasticsearch.search.aggregations.support.ValuesSourceRegistry;
2828
import org.elasticsearch.search.aggregations.support.ValuesSourceType;
29+
import org.elasticsearch.search.sort.SortOrder;
2930

3031
import java.io.IOException;
3132
import java.util.Map;
@@ -34,8 +35,9 @@
3435
public class GeoLineAggregationBuilder
3536
extends MultiValuesSourceAggregationBuilder.LeafOnly<GeoLineAggregationBuilder> {
3637

37-
static final ParseField GEO_POINT_FIELD = new ParseField("geo_point");
38+
static final ParseField POINT_FIELD = new ParseField("point");
3839
static final ParseField SORT_FIELD = new ParseField("sort");
40+
static final ParseField ORDER_FIELD = new ParseField("sort_order");
3941
static final ParseField INCLUDE_SORT_FIELD = new ParseField("include_sort");
4042

4143
public static final String NAME = "geo_line";
@@ -44,12 +46,14 @@ public class GeoLineAggregationBuilder
4446
ObjectParser.fromBuilder(NAME, GeoLineAggregationBuilder::new);
4547
static {
4648
MultiValuesSourceParseHelper.declareCommon(PARSER, true, ValueType.NUMERIC);
47-
MultiValuesSourceParseHelper.declareField(GEO_POINT_FIELD.getPreferredName(), PARSER, true, false, false);
49+
MultiValuesSourceParseHelper.declareField(POINT_FIELD.getPreferredName(), PARSER, true, false, false);
4850
MultiValuesSourceParseHelper.declareField(SORT_FIELD.getPreferredName(), PARSER, true, false, false);
51+
PARSER.declareString((builder, order) -> builder.sortOrder(SortOrder.fromString(order)), ORDER_FIELD);
4952
PARSER.declareBoolean(GeoLineAggregationBuilder::includeSort, INCLUDE_SORT_FIELD);
5053
}
5154

5255
private boolean includeSort;
56+
private SortOrder sortOrder = SortOrder.ASC;
5357

5458
public static void registerUsage(ValuesSourceRegistry.Builder builder) {
5559
builder.registerUsage(NAME, CoreValuesSourceType.GEOPOINT);
@@ -69,13 +73,20 @@ private GeoLineAggregationBuilder(GeoLineAggregationBuilder clone,
6973
*/
7074
public GeoLineAggregationBuilder(StreamInput in) throws IOException {
7175
super(in);
76+
sortOrder = SortOrder.readFromStream(in);
77+
includeSort = in.readBoolean();
7278
}
7379

7480
public GeoLineAggregationBuilder includeSort(boolean includeSort) {
7581
this.includeSort = includeSort;
7682
return this;
7783
}
7884

85+
public GeoLineAggregationBuilder sortOrder(SortOrder sortOrder) {
86+
this.sortOrder = sortOrder;
87+
return this;
88+
}
89+
7990
@Override
8091
protected AggregationBuilder shallowCopy(AggregatorFactories.Builder factoriesBuilder, Map<String, Object> metaData) {
8192
return new GeoLineAggregationBuilder(this, factoriesBuilder, metaData);
@@ -87,8 +98,9 @@ public BucketCardinality bucketCardinality() {
8798
}
8899

89100
@Override
90-
protected void innerWriteTo(StreamOutput out) {
91-
// Do nothing, no extra state to write to stream
101+
protected void innerWriteTo(StreamOutput out) throws IOException {
102+
sortOrder.writeTo(out);
103+
out.writeBoolean(includeSort);
92104
}
93105

94106
@Override
@@ -97,18 +109,19 @@ protected ValuesSourceType defaultValueSourceType() {
97109
}
98110

99111
@Override
100-
protected MultiValuesSourceAggregatorFactory innerBuild(QueryShardContext queryShardContext,
112+
protected MultiValuesSourceAggregatorFactory innerBuild(AggregationContext aggregationContext,
101113
Map<String, ValuesSourceConfig> configs,
102114
Map<String, QueryBuilder> filters,
103115
DocValueFormat format,
104116
AggregatorFactory parent,
105117
AggregatorFactories.Builder subFactoriesBuilder) throws IOException {
106-
return new GeoLineAggregatorFactory(name, configs, format, queryShardContext, parent, subFactoriesBuilder, metadata, includeSort);
118+
return new GeoLineAggregatorFactory(name, configs, format, aggregationContext, parent, subFactoriesBuilder, metadata,
119+
includeSort, sortOrder);
107120
}
108121

109122
public GeoLineAggregationBuilder value(MultiValuesSourceFieldConfig valueConfig) {
110-
valueConfig = Objects.requireNonNull(valueConfig, "Configuration for field [" + GEO_POINT_FIELD + "] cannot be null");
111-
field(GEO_POINT_FIELD.getPreferredName(), valueConfig);
123+
valueConfig = Objects.requireNonNull(valueConfig, "Configuration for field [" + POINT_FIELD + "] cannot be null");
124+
field(POINT_FIELD.getPreferredName(), valueConfig);
112125
return this;
113126
}
114127

0 commit comments

Comments
 (0)