Make sure SortBuilders rewrite inner nested sorts (#26532)
The three SortBuilders that can have inner NestedSortBuilders currently don't rewrite any of the filters contained in them. This change adds a rewrite method to NestedSortBuilder and changes rewriting in FieldSortBuilder, ScriptSortBuilder and GeoDistanceSortBuilder to make sure inner nested sorts get rewritten if they need to.
This commit is contained in:
parent
6f69b25f61
commit
ba02485541
|
@ -83,6 +83,7 @@ public interface QueryBuilder extends NamedWriteable, ToXContentObject, Rewritea
|
|||
* Rewrites this query builder into its primitive form. By default this method return the builder itself. If the builder
|
||||
* did not change the identity reference must be returned otherwise the builder will be rewritten infinitely.
|
||||
*/
|
||||
@Override
|
||||
default QueryBuilder rewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -409,13 +409,21 @@ public class FieldSortBuilder extends SortBuilder<FieldSortBuilder> {
|
|||
|
||||
@Override
|
||||
public FieldSortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
if (nestedFilter == null) {
|
||||
if (nestedFilter == null && nestedSort == null) {
|
||||
return this;
|
||||
}
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
if (nestedFilter != null) {
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new FieldSortBuilder(this).setNestedFilter(rewrite);
|
||||
} else {
|
||||
NestedSortBuilder rewrite = nestedSort.rewrite(ctx);
|
||||
if (nestedSort == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new FieldSortBuilder(this).setNestedSort(rewrite);
|
||||
}
|
||||
return new FieldSortBuilder(this).setNestedFilter(rewrite);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -681,14 +681,22 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
if (nestedFilter == null) {
|
||||
public GeoDistanceSortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
if (nestedFilter == null && nestedSort == null) {
|
||||
return this;
|
||||
}
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
if (nestedFilter != null) {
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new GeoDistanceSortBuilder(this).setNestedFilter(rewrite);
|
||||
} else {
|
||||
NestedSortBuilder rewrite = nestedSort.rewrite(ctx);
|
||||
if (nestedSort == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new GeoDistanceSortBuilder(this).setNestedSort(rewrite);
|
||||
}
|
||||
return new GeoDistanceSortBuilder(this).setNestedFilter(rewrite);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.ToXContentObject;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
@ -149,4 +150,23 @@ public class NestedSortBuilder implements Writeable, ToXContentObject {
|
|||
public int hashCode() {
|
||||
return Objects.hash(path, filter, nestedSort);
|
||||
}
|
||||
|
||||
public NestedSortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
if (filter == null && nestedSort == null) {
|
||||
return this;
|
||||
}
|
||||
QueryBuilder rewriteFilter = this.filter;
|
||||
NestedSortBuilder rewriteNested = this.nestedSort;
|
||||
if (filter != null) {
|
||||
rewriteFilter = filter.rewrite(ctx);
|
||||
}
|
||||
if (nestedSort != null) {
|
||||
rewriteNested = nestedSort.rewrite(ctx);
|
||||
}
|
||||
if (rewriteFilter != this.filter || rewriteNested != this.nestedSort) {
|
||||
return new NestedSortBuilder(this.path).setFilter(rewriteFilter).setNestedSort(rewriteNested);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ public class ScoreSortBuilder extends SortBuilder<ScoreSortBuilder> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
public ScoreSortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -451,13 +451,21 @@ public class ScriptSortBuilder extends SortBuilder<ScriptSortBuilder> {
|
|||
|
||||
@Override
|
||||
public ScriptSortBuilder rewrite(QueryRewriteContext ctx) throws IOException {
|
||||
if (nestedFilter == null) {
|
||||
if (nestedFilter == null && nestedSort == null) {
|
||||
return this;
|
||||
}
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
if (nestedFilter != null) {
|
||||
QueryBuilder rewrite = nestedFilter.rewrite(ctx);
|
||||
if (nestedFilter == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new ScriptSortBuilder(this).setNestedFilter(rewrite);
|
||||
} else {
|
||||
NestedSortBuilder rewrite = nestedSort.rewrite(ctx);
|
||||
if (nestedSort == rewrite) {
|
||||
return this;
|
||||
}
|
||||
return new ScriptSortBuilder(this).setNestedSort(rewrite);
|
||||
}
|
||||
return new ScriptSortBuilder(this).setNestedFilter(rewrite);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,13 @@ import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.N
|
|||
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.TypeFieldMapper;
|
||||
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.QueryShardException;
|
||||
import org.elasticsearch.index.query.RangeQueryBuilder;
|
||||
import org.elasticsearch.search.DocValueFormat;
|
||||
import org.elasticsearch.search.MultiValueMode;
|
||||
|
||||
|
@ -367,6 +371,40 @@ public class FieldSortBuilderTests extends AbstractSortTestCase<FieldSortBuilder
|
|||
assertEquals("Setting both nested_path/nested_filter and nested not allowed", iae.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested Filter gets rewritten
|
||||
*/
|
||||
public void testNestedRewrites() throws IOException {
|
||||
FieldSortBuilder sortBuilder = new FieldSortBuilder(MAPPED_STRING_FIELDNAME);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedPath("path").setNestedFilter(rangeQuery);
|
||||
FieldSortBuilder rewritten = (FieldSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedFilter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested sort gets rewritten
|
||||
*/
|
||||
public void testNestedSortRewrites() throws IOException {
|
||||
FieldSortBuilder sortBuilder = new FieldSortBuilder(MAPPED_STRING_FIELDNAME);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedSort(new NestedSortBuilder("path").setFilter(rangeQuery));
|
||||
FieldSortBuilder rewritten = (FieldSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedSort().getFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertWarnings(FieldSortBuilder testItem) {
|
||||
List<String> expectedWarnings = new ArrayList<>();
|
||||
|
|
|
@ -39,8 +39,12 @@ import org.elasticsearch.index.mapper.MappedFieldType;
|
|||
import org.elasticsearch.index.mapper.TypeFieldMapper;
|
||||
import org.elasticsearch.index.query.GeoValidationMethod;
|
||||
import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.RangeQueryBuilder;
|
||||
import org.elasticsearch.search.DocValueFormat;
|
||||
import org.elasticsearch.search.MultiValueMode;
|
||||
import org.elasticsearch.test.geo.RandomGeoGenerator;
|
||||
|
@ -581,7 +585,40 @@ public class GeoDistanceSortBuilderTests extends AbstractSortTestCase<GeoDistanc
|
|||
iae = expectThrows(IllegalArgumentException.class,
|
||||
() -> sortBuilder.setNestedSort(new NestedSortBuilder("otherPath")).setNestedFilter(QueryBuilders.matchAllQuery()));
|
||||
assertEquals("Setting both nested_path/nested_filter and nested not allowed", iae.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested Filter gets rewritten
|
||||
*/
|
||||
public void testNestedRewrites() throws IOException {
|
||||
GeoDistanceSortBuilder sortBuilder = new GeoDistanceSortBuilder("fieldName", 0.0, 0.0);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedPath("path").setNestedFilter(rangeQuery);
|
||||
GeoDistanceSortBuilder rewritten = (GeoDistanceSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedFilter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested sort gets rewritten
|
||||
*/
|
||||
public void testNestedSortRewrites() throws IOException {
|
||||
GeoDistanceSortBuilder sortBuilder = new GeoDistanceSortBuilder("fieldName", 0.0, 0.0);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedSort(new NestedSortBuilder("path").setFilter(rangeQuery));
|
||||
GeoDistanceSortBuilder rewritten = (GeoDistanceSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedSort().getFilter());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,11 +27,17 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
|
||||
import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.search.SearchModule;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.EqualsHashCodeTestUtils;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -136,4 +142,64 @@ public class NestedSortBuilderTests extends ESTestCase {
|
|||
NestedSortBuilderTests::mutate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that filters and inner nested sorts get rewritten
|
||||
*/
|
||||
public void testRewrite() throws IOException {
|
||||
QueryBuilder filterThatRewrites = new MatchNoneQueryBuilder() {
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(org.elasticsearch.index.query.QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchAllQueryBuilder();
|
||||
};
|
||||
};
|
||||
// test that filter gets rewritten
|
||||
NestedSortBuilder original = new NestedSortBuilder("path").setFilter(filterThatRewrites);
|
||||
QueryRewriteContext mockRewriteContext = Mockito.mock(QueryRewriteContext.class);
|
||||
NestedSortBuilder rewritten = original.rewrite(mockRewriteContext);
|
||||
assertNotSame(rewritten, original);
|
||||
assertNotSame(rewritten.getFilter(), original.getFilter());
|
||||
|
||||
// test that inner nested sort gets rewritten
|
||||
original = new NestedSortBuilder("path");
|
||||
original.setNestedSort(new NestedSortBuilder("otherPath").setFilter(filterThatRewrites));
|
||||
rewritten = original.rewrite(mockRewriteContext);
|
||||
assertNotSame(rewritten, original);
|
||||
assertNotSame(rewritten.getNestedSort(), original.getNestedSort());
|
||||
|
||||
// test that both filter and inner nested sort get rewritten
|
||||
original = new NestedSortBuilder("path");
|
||||
original.setFilter(filterThatRewrites);
|
||||
original.setNestedSort(new NestedSortBuilder("otherPath").setFilter(filterThatRewrites));
|
||||
rewritten = original.rewrite(mockRewriteContext);
|
||||
assertNotSame(rewritten, original);
|
||||
assertNotSame(rewritten.getFilter(), original.getFilter());
|
||||
assertNotSame(rewritten.getNestedSort(), original.getNestedSort());
|
||||
|
||||
// test that original stays unchanged if no element rewrites
|
||||
original = new NestedSortBuilder("path");
|
||||
original.setFilter(new MatchNoneQueryBuilder());
|
||||
original.setNestedSort(new NestedSortBuilder("otherPath").setFilter(new MatchNoneQueryBuilder()));
|
||||
rewritten = original.rewrite(mockRewriteContext);
|
||||
assertSame(rewritten, original);
|
||||
assertSame(rewritten.getFilter(), original.getFilter());
|
||||
assertSame(rewritten.getNestedSort(), original.getNestedSort());
|
||||
|
||||
// test that rewrite works recursively
|
||||
original = new NestedSortBuilder("firstLevel");
|
||||
ConstantScoreQueryBuilder constantScoreQueryBuilder = new ConstantScoreQueryBuilder(filterThatRewrites);
|
||||
original.setFilter(constantScoreQueryBuilder);
|
||||
NestedSortBuilder nestedSortThatRewrites = new NestedSortBuilder("thirdLevel")
|
||||
.setFilter(filterThatRewrites);
|
||||
original.setNestedSort(new NestedSortBuilder("secondLevel").setNestedSort(nestedSortThatRewrites));
|
||||
rewritten = original.rewrite(mockRewriteContext);
|
||||
assertNotSame(rewritten, original);
|
||||
assertNotSame(rewritten.getFilter(), constantScoreQueryBuilder);
|
||||
assertNotSame(((ConstantScoreQueryBuilder) rewritten.getFilter()).innerQuery(), constantScoreQueryBuilder.innerQuery());
|
||||
|
||||
assertEquals("secondLevel", rewritten.getNestedSort().getPath());
|
||||
assertNotSame(rewritten.getNestedSort(), original.getNestedSort());
|
||||
assertEquals("thirdLevel", rewritten.getNestedSort().getNestedSort().getPath());
|
||||
assertNotSame(rewritten.getNestedSort().getNestedSort(), nestedSortThatRewrites);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ import org.elasticsearch.index.fielddata.fieldcomparator.DoubleValuesComparatorS
|
|||
import org.elasticsearch.index.mapper.TypeFieldMapper;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.RangeQueryBuilder;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
import org.elasticsearch.search.DocValueFormat;
|
||||
|
@ -353,6 +357,40 @@ public class ScriptSortBuilderTests extends AbstractSortTestCase<ScriptSortBuild
|
|||
iae = expectThrows(IllegalArgumentException.class,
|
||||
() -> sortBuilder.setNestedSort(new NestedSortBuilder("otherPath")).setNestedFilter(QueryBuilders.matchAllQuery()));
|
||||
assertEquals("Setting both nested_path/nested_filter and nested not allowed", iae.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested Filter gets rewritten
|
||||
*/
|
||||
public void testNestedRewrites() throws IOException {
|
||||
ScriptSortBuilder sortBuilder = new ScriptSortBuilder(mockScript("something"), ScriptSortType.STRING);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedPath("path").setNestedFilter(rangeQuery);
|
||||
ScriptSortBuilder rewritten = (ScriptSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedFilter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the the nested sort gets rewritten
|
||||
*/
|
||||
public void testNestedSortRewrites() throws IOException {
|
||||
ScriptSortBuilder sortBuilder = new ScriptSortBuilder(mockScript("something"), ScriptSortType.STRING);
|
||||
RangeQueryBuilder rangeQuery = new RangeQueryBuilder("fieldName") {
|
||||
@Override
|
||||
public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
};
|
||||
sortBuilder.setNestedSort(new NestedSortBuilder("path").setFilter(rangeQuery));
|
||||
ScriptSortBuilder rewritten = (ScriptSortBuilder) sortBuilder
|
||||
.rewrite(createMockShardContext());
|
||||
assertNotSame(rangeQuery, rewritten.getNestedSort().getFilter());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue