Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2536723
Add initial structure for ST_CENTROID
craigtaverner Jan 9, 2024
b80c495
Revert "Revert stab at implementing forStats for doc-values vs source"
craigtaverner Jan 9, 2024
5b12397
Refined csv-spect tests with st_centroid
craigtaverner Jan 9, 2024
213c138
Spotless disagrees with intellij
craigtaverner Jan 9, 2024
3c6731b
Fixes after reverting fieldmapper code to test GeoPointFieldMapper
craigtaverner Jan 9, 2024
4297c93
Get GeoPointFieldMapperTests working again after enabling doc-values …
craigtaverner Jan 10, 2024
09b3109
Simplify after rebase on main
craigtaverner Jan 10, 2024
da0c312
Support local physical planning of forStats attributes for spatial ag…
craigtaverner Jan 12, 2024
4366bc2
Get st_centroid aggregation working on doc-values
craigtaverner Jan 12, 2024
a279e34
Create both DocValues and SourceValues versions of st_centroid
craigtaverner Jan 12, 2024
00dcdd7
Support physical planning of DocValues and SourceValues SpatialCentroid
craigtaverner Jan 12, 2024
07e16d1
Improve test for physical planning of DocValues in SpatialCentroid
craigtaverner Jan 13, 2024
a18aa6e
Fixed show functions for st_centroid
craigtaverner Jan 13, 2024
fe3452d
More st_centroid tests with mv_expand
craigtaverner Jan 15, 2024
c61901d
Fix st_centroid from point literals
craigtaverner Jan 15, 2024
68ad574
Teach CsvTests to handle spatial types alternative loading from doc-v…
craigtaverner Jan 15, 2024
ec82452
Fixed failing NodeSubclassTests
craigtaverner Jan 15, 2024
6239f2f
More complex st_centroid tests and fixed bug with multiple aggs
craigtaverner Jan 15, 2024
1489df3
Update docs/changelog/104218.yaml
craigtaverner Jan 16, 2024
558c2ef
Fix automatically generated changelog file
craigtaverner Jan 16, 2024
c884de2
Fixed failing test
craigtaverner Jan 16, 2024
b72b6d4
More tests covering more combinations including MV_EXPAND and grouping
craigtaverner Jan 16, 2024
fdd5429
Added cartesian st_centroid with grouping test
craigtaverner Jan 16, 2024
1fffba4
Reduce flaky tests by sorting results
craigtaverner Jan 16, 2024
5ea442a
Reduce flaky tests by sorting results
craigtaverner Jan 16, 2024
47f8cc3
Added tests for stats on stats to ensure planner coped
craigtaverner Jan 16, 2024
efb091b
Add unit tests to ensure doc-values in query planning complex cases
craigtaverner Jan 16, 2024
a3a2526
Some minor updates from code review
craigtaverner Jan 16, 2024
e89a2e4
Fixes after rebase on main
craigtaverner Jan 17, 2024
918dfeb
Merge remote-tracking branch 'origin/main' into esql_point_doc_values
craigtaverner Jan 17, 2024
8bde869
Get correct error message on unsupported geo_shape for st_centroid
craigtaverner Jan 17, 2024
01f8eb5
Refined point vs shape differences after merging main
craigtaverner Jan 17, 2024
4a75df2
Added basic docs
craigtaverner Jan 17, 2024
4bc596a
Delete docs/changelog/104218.yaml
craigtaverner Jan 17, 2024
ef1f214
Revert "Delete docs/changelog/104218.yaml"
craigtaverner Jan 17, 2024
1ecbdae
Fixed broken docs tag link
craigtaverner Jan 17, 2024
b760d19
Simplify BlockReaderSupport in MapperTestCase from code review
craigtaverner Jan 18, 2024
9aed84e
Moved spatial aggregations into a sub-package
craigtaverner Jan 18, 2024
a8ad9fd
Merge remote-tracking branch 'origin/main' into esql_point_doc_values
craigtaverner Jan 18, 2024
f8c2890
Added some more code review updates, including nested tests
craigtaverner Jan 18, 2024
90b500f
Get nested functions working, if only from source values for now
craigtaverner Jan 18, 2024
254b85b
Merge remote-tracking branch 'origin/main' into esql_point_doc_values
craigtaverner Jan 18, 2024
8f4d00e
Code review update
craigtaverner Jan 18, 2024
e1ea6d5
Code review update
craigtaverner Jan 18, 2024
dcd137c
Added second location column to airports for wider testing
craigtaverner Jan 18, 2024
3e0a3c1
Use second location in tests, including nulls
craigtaverner Jan 18, 2024
4997775
Fixed bug supporting multi spatial aggregations in the local node
craigtaverner Jan 18, 2024
00d44e2
Renamed forStats to fieldExtractPreference for clarity
craigtaverner Jan 22, 2024
ee3ba02
Merge remote-tracking branch 'origin/main' into esql_point_doc_values
craigtaverner Jan 22, 2024
ef5b7e4
EsqlSpecIT was failing on very high precision centroids on different …
craigtaverner Jan 23, 2024
12c6980
Delete docs/changelog/104218.yaml
craigtaverner Jan 23, 2024
3646147
Revert "Delete docs/changelog/104218.yaml"
craigtaverner Jan 23, 2024
088cbf2
Fixed changelog entry
craigtaverner Jan 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ public String indexName() {
return "benchmark";
}

@Override
public boolean forStats() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've considered alternative names, like forDisplay (opposite of for stats), but every choice has pros and cons, so I've left it like this for now, since this most closely matches current needs.

If we start using this for non-stats use cases, like spatial predicates that benefit from doc-values, we can change the name of the method at that point.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Predicate and top-n run on the results of functions consuming the points will want it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite looking at the PR , I still find the method name confusing.
Instead of telling it who should be using it, how about describing its role? e.g. loadAsDocValues or loadAsColumn, etc...

return false;
}

@Override
public SearchLookup lookup() {
throw new UnsupportedOperationException();
Expand Down
5 changes: 5 additions & 0 deletions docs/changelog/104218.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 104218
summary: "Support reading spatial points from doc-values for STATS"
area: "ES|QL"
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The <<esql-stats-by>> function supports these aggregate functions:
* <<esql-agg-median-absolute-deviation>>
* <<esql-agg-min>>
* <<esql-agg-percentile>>
* <<esql-agg-st-centroid>>
* <<esql-agg-sum>>
// end::agg_list[]

Expand All @@ -27,4 +28,5 @@ include::median.asciidoc[]
include::median-absolute-deviation.asciidoc[]
include::min.asciidoc[]
include::percentile.asciidoc[]
include::st_centroid.asciidoc[]
include::sum.asciidoc[]
18 changes: 18 additions & 0 deletions docs/reference/esql/functions/st_centroid.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[discrete]
[[esql-agg-st-centroid]]
=== `ST_CENTROID`

Calculate the spatial centroid over a field with spatial point geometry type.

[source.merge.styled,esql]
----
include::{esql-specs}/spatial.csv-spec[tag=st_centroid-airports]
----
[%header.monospaced.styled,format=dsv,separator=|]
|===
include::{esql-specs}/spatial.csv-spec[tag=st_centroid-airports-result]
|===

Supported types:

include::types/st_centroid.asciidoc[]
4 changes: 4 additions & 0 deletions docs/reference/esql/functions/to_cartesianpoint.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ include::{esql-specs}/spatial.csv-spec[tag=to_cartesianpoint-str]
|===
include::{esql-specs}/spatial.csv-spec[tag=to_cartesianpoint-str-result]
|===

Supported types:

include::types/to_cartesianpoint.asciidoc[]
4 changes: 4 additions & 0 deletions docs/reference/esql/functions/to_geopoint.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ include::{esql-specs}/spatial.csv-spec[tag=to_geopoint-str]
|===
include::{esql-specs}/spatial.csv-spec[tag=to_geopoint-str-result]
|===

Supported types:

include::types/to_geopoint.asciidoc[]
6 changes: 6 additions & 0 deletions docs/reference/esql/functions/types/st_centroid.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
v | result
geo_point | geo_point
cartesian_point | cartesian_point
|===
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
v | result
cartesian_point | cartesian_point
keyword | cartesian_point
text | cartesian_point
|===
7 changes: 7 additions & 0 deletions docs/reference/esql/functions/types/to_geopoint.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[%header.monospaced.styled,format=dsv,separator=|]
|===
v | result
geo_point | geo_point
keyword | geo_point
text | geo_point
|===
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ protected IngestScriptSupport ingestScriptSupport() {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit but you change the return type as well: protected Function<Object, BytesRef>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow? I just reverted this method to the version before Luigi's PR. Neither his change nor mine changed the return type.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just saying that it might be helpful to expose the type in the method signature protected Function<Object, BytesRef>.
it's used in testing so it might not matter in the end.

return v -> ((BytesRef) v).utf8ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ public List<SyntheticSourceInvalidExample> invalidExample() throws IOException {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> (Number) v;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ protected Object parseSourceValue(Object value) {
@Override
public BlockLoader blockLoader(BlockLoaderContext blContext) {
// Currently we can only load from source in ESQL
return blockLoaderFromSource(blContext);
}

protected BlockLoader blockLoaderFromSource(BlockLoaderContext blContext) {
ValueFetcher fetcher = valueFetcher(blContext.sourcePaths(name()), nullValue, GeometryFormatterFactory.WKB);
// TODO consider optimization using BlockSourceReader.lookupFromFieldNames(blContext.fieldNames(), name())
return new BlockSourceReader.GeometriesBlockLoader(fetcher, BlockSourceReader.lookupMatchingAll());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,13 @@ protected AbstractPointFieldType(
protected Object nullValueAsSource(T nullValue) {
return nullValue == null ? null : nullValue.toWKT();
}

@Override
public BlockLoader blockLoader(BlockLoaderContext blContext) {
if (blContext.forStats() && hasDocValues()) {
return new BlockDocValuesReader.LongsBlockLoader(name());
}
return blockLoaderFromSource(blContext);
}
Comment on lines +181 to +188

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use the ternary operator to make this a one-liner:
return blContext.asDocValues() && hasDocValues() ? new BlockDocValuesReader.LongsBlockLoader(name()) : blockLoaderFromSource(blContext)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,14 @@ public interface BlockLoaderContext {
*/
String indexName();

/**
* Whether the data will be used in stats.
* This is relevant to some types, where the choice between doc-values or reading from source is dependent on the usage.
* For example, spatial types use doc-values for stats, but read from source for search because doc-values are modified
* from the original.
*/
boolean forStats();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above - e.g. preferDocValues()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is confusing for me here is that we'll set this value to false by default, and only set it to true for spatial aggregations loaded from fields. That makes complete sense for the spatial field mappers block loading, but all other types will get a BlockLoaderContext with preferDocValues==false, while simultaneously ignoring that, and preferring to load doc-values.

The term forStats is not making any statement about whether that implies anything about doc-values versus source loading, and the decision to load differently is entirely local to the field mapper.

All other types can say 'you don't want to use this for stats, well both doc-values and source are equally good enough for non-stats, so I'll load the one I think is fastest'. But if we call it preferDocValues==false, then all the other non-spatial types are basically saying "I know I've been told NOT to prefer doc-values, but I'm going to ignore that because I magically know this is not relevant to me".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about useDocValues(), loadDocValues, etc...? My point is forStats doesn't tell much.


/**
* {@link SearchLookup} used for building scripts.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public List<SyntheticSourceInvalidExample> invalidExample() throws IOException {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
// Just assert that we expect a boolean. Otherwise no munging.
return v -> (Boolean) v;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ public void execute() {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> ((Number) v).longValue();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed)
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> {
// The test converts the float into a string so we do do
Number n = (Number) v;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,11 @@ public void testScriptAndPrecludedParameters() {

@Override
protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed) {
return syntheticSourceSupport(ignoreMalformed, false);
}

@Override
protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed, boolean columnReader) {
assumeFalse("synthetic _source for geo_point doesn't support ignore_malformed", ignoreMalformed);
return new SyntheticSourceSupport() {
private final boolean ignoreZValue = usually();
Expand All @@ -607,6 +612,9 @@ protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed)
public SyntheticSourceExample example(int maxVals) {
if (randomBoolean()) {
Tuple<Object, GeoPoint> v = generateValue();
if (columnReader) {
return new SyntheticSourceExample(v.v1(), decode(encode(v.v2())), encode(v.v2()), this::mapping);
}
return new SyntheticSourceExample(v.v1(), v.v2(), v.v2().toWKT(), this::mapping);
}
List<Tuple<Object, GeoPoint>> values = randomList(1, maxVals, this::generateValue);
Expand All @@ -616,12 +624,20 @@ public SyntheticSourceExample example(int maxVals) {
.sorted((a, b) -> Long.compare(encode(a.v2()), encode(b.v2())))
.toList();
List<Object> in = sorted.stream().map(Tuple::v1).toList();
List<GeoPoint> outList = sorted.stream().map(v -> encode(v.v2())).sorted().map(this::decode).toList();
List<GeoPoint> outList = sorted.stream().map(Tuple::v2).toList();
Object out = outList.size() == 1 ? outList.get(0) : outList;

List<String> outBlockList = outList.stream().map(GeoPoint::toWKT).toList();
Object outBlock = outBlockList.size() == 1 ? outBlockList.get(0) : outBlockList;
return new SyntheticSourceExample(in, out, outBlock, this::mapping);
if (columnReader) {
// When reading doc-values, the block is a list of encoded longs
List<Long> outBlockList = outList.stream().map(this::encode).toList();
Object outBlock = outBlockList.size() == 1 ? outBlockList.get(0) : outBlockList;
return new SyntheticSourceExample(in, out, outBlock, this::mapping);
} else {
// When reading row-stride, the block is a list of WKT encoded BytesRefs
List<String> outBlockList = outList.stream().map(GeoPoint::toWKT).toList();
Object outBlock = outBlockList.size() == 1 ? outBlockList.get(0) : outBlockList;
return new SyntheticSourceExample(in, out, outBlock, this::mapping);
}
}

private Tuple<Object, GeoPoint> generateValue() {
Expand Down Expand Up @@ -705,13 +721,18 @@ protected IngestScriptSupport ingestScriptSupport() {
throw new AssumptionViolatedException("not supported");
}

private boolean useDocValues = false;
@Override
protected Function<Object, Object> loadBlockExpected() {
throw new IllegalStateException("Should never reach here, call loadBlockExpected(BlockReaderSupport, boolean) instead");
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
if (useDocValues) {
protected Function<Object, Object> loadBlockExpected(BlockReaderSupport blockReaderSupport, boolean columnReader) {
if (columnReader) {
// When using column reader, we expect the output to be doc-values (which means encoded longs)
return v -> asJacksonNumberOutput(((Number) v).longValue());
} else {
// When using row-stride reader, we expect the output to be WKT encoded BytesRef
return v -> asWKT((BytesRef) v);
}
}
Expand All @@ -732,13 +753,8 @@ protected static Object asWKT(BytesRef value) {
}

@Override
protected boolean supportsColumnAtATimeReader(MapperService mapper, MappedFieldType ft) {
// Currently ESQL support for geo_point is limited to source values
return false;
}

@Override
public void testBlockLoaderFromRowStrideReaderWithSyntheticSource() {
assumeTrue("Synthetic source not completed supported for geo_point", false);
protected BlockReaderSupport getSupportedReaders(MapperService mapper, String loaderFieldName) {
MappedFieldType ft = mapper.fieldType(loaderFieldName);
return new BlockReaderSupport(ft.hasDocValues(), true, false, mapper, loaderFieldName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ protected SyntheticSourceSupport syntheticSourceSupport(boolean ignoreMalformed)
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> {
// The test converts the float into a string so we do do
Number n = (Number) v;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ public void execute() {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> InetAddresses.toAddrString(InetAddressPoint.decode(BytesRef.deepCopyOf((BytesRef) v).bytes));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ protected boolean supportsIgnoreMalformed() {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return v -> ((BytesRef) v).utf8ToString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public void testFetchCoerced() throws IOException {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return n -> {
Number number = ((Number) n);
if (Integer.MIN_VALUE <= number.longValue() && number.longValue() <= Integer.MAX_VALUE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public void testAllowMultipleValuesField() throws IOException {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String loaderFieldName) {
protected Function<Object, Object> loadBlockExpected() {
return n -> ((Number) n); // Just assert it's a number
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,8 +1195,8 @@ public List<SyntheticSourceInvalidExample> invalidExample() throws IOException {
}

@Override
protected Function<Object, Object> loadBlockExpected(MapperService mapper, String fieldName) {
if (nullLoaderExpected(mapper, fieldName)) {
protected Function<Object, Object> loadBlockExpected(BlockReaderSupport blockReaderSupport, boolean columnReader) {
if (nullLoaderExpected(blockReaderSupport.mapper(), blockReaderSupport.loaderFieldName())) {
return null;
}
return v -> ((BytesRef) v).utf8ToString();
Expand Down Expand Up @@ -1352,20 +1352,22 @@ public void testEmpty() throws Exception {
}

@Override
protected boolean supportsColumnAtATimeReader(MapperService mapper, MappedFieldType ft) {
protected BlockReaderSupport getSupportedReaders(MapperService mapper, String loaderFieldName) {
MappedFieldType ft = mapper.fieldType(loaderFieldName);
String parentName = mapper.mappingLookup().parentField(ft.name());
if (parentName == null) {
TextFieldMapper.TextFieldType text = (TextFieldType) ft;
return text.syntheticSourceDelegate() != null
boolean supportsColumnAtATimeReader = text.syntheticSourceDelegate() != null
&& text.syntheticSourceDelegate().hasDocValues()
&& text.canUseSyntheticSourceDelegateForQuerying();
return new BlockReaderSupport(supportsColumnAtATimeReader, mapper, loaderFieldName);
}
MappedFieldType parent = mapper.fieldType(parentName);
if (false == parent.typeName().equals(KeywordFieldMapper.CONTENT_TYPE)) {
throw new UnsupportedOperationException();
}
KeywordFieldMapper.KeywordFieldType kwd = (KeywordFieldMapper.KeywordFieldType) parent;
return kwd.hasDocValues();
return new BlockReaderSupport(kwd.hasDocValues(), mapper, loaderFieldName);
}

public void testBlockLoaderFromParentColumnReader() throws IOException {
Expand Down Expand Up @@ -1398,6 +1400,7 @@ private void testBlockLoaderFromParent(boolean columnReader, boolean syntheticSo
b.endObject();
};
MapperService mapper = createMapperService(syntheticSource ? syntheticSourceMapping(buildFields) : mapping(buildFields));
testBlockLoader(columnReader, example, mapper, "field.sub");
BlockReaderSupport blockReaderSupport = getSupportedReaders(mapper, "field.sub");
testBlockLoader(columnReader, example, blockReaderSupport);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ public String indexName() {
throw new UnsupportedOperationException();
}

@Override
public boolean forStats() {
return false;
}

@Override
public SearchLookup lookup() {
return mockContext().lookup();
Expand Down
Loading