nested sorting: If sorting by nested field then the `nested_path` should always be specified.
Closes #13420
This commit is contained in:
parent
89159f073c
commit
2eadc6d595
|
@ -168,17 +168,6 @@ public class GeoDistanceSortParser implements SortParser {
|
||||||
distances[i] = geoDistance.fixedSourceDistance(geoPoints.get(i).lat(), geoPoints.get(i).lon(), unit);
|
distances[i] = geoDistance.fixedSourceDistance(geoPoints.get(i).lat(), geoPoints.get(i).lon(), unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this in master, we should be explicit when we want to sort on nested fields and don't do anything automatically
|
|
||||||
if (nestedHelper == null || nestedHelper.getNestedObjectMapper() == null) {
|
|
||||||
ObjectMapper objectMapper = context.mapperService().resolveClosestNestedObjectMapper(fieldName);
|
|
||||||
if (objectMapper != null && objectMapper.nested().isNested()) {
|
|
||||||
if (nestedHelper == null) {
|
|
||||||
nestedHelper = new NestedInnerQueryParseSupport(context.queryParserService().getParseContext());
|
|
||||||
}
|
|
||||||
nestedHelper.setPath(objectMapper.fullPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Nested nested;
|
final Nested nested;
|
||||||
if (nestedHelper != null && nestedHelper.getPath() != null) {
|
if (nestedHelper != null && nestedHelper.getPath() != null) {
|
||||||
|
|
||||||
|
|
|
@ -237,19 +237,6 @@ public class SortParseElement implements SearchParseElement {
|
||||||
sortMode = resolveDefaultSortMode(reverse);
|
sortMode = resolveDefaultSortMode(reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this in master, we should be explicit when we want to sort on nested fields and don't do anything automatically
|
|
||||||
if (!(context instanceof SubSearchContext)) {
|
|
||||||
// Only automatically resolve nested path when sort isn't defined for top_hits
|
|
||||||
if (nestedHelper == null || nestedHelper.getNestedObjectMapper() == null) {
|
|
||||||
ObjectMapper objectMapper = context.mapperService().resolveClosestNestedObjectMapper(fieldName);
|
|
||||||
if (objectMapper != null && objectMapper.nested().isNested()) {
|
|
||||||
if (nestedHelper == null) {
|
|
||||||
nestedHelper = new NestedInnerQueryParseSupport(context.queryParserService().getParseContext());
|
|
||||||
}
|
|
||||||
nestedHelper.setPath(objectMapper.fullPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Nested nested;
|
final Nested nested;
|
||||||
if (nestedHelper != null && nestedHelper.getPath() != null) {
|
if (nestedHelper != null && nestedHelper.getPath() != null) {
|
||||||
BitSetProducer rootDocumentsFilter = context.bitsetFilterCache().getBitSetProducer(Queries.newNonNestedFilter());
|
BitSetProducer rootDocumentsFilter = context.bitsetFilterCache().getBitSetProducer(Queries.newNonNestedFilter());
|
||||||
|
|
|
@ -384,7 +384,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
SearchResponse searchResponse = client().prepareSearch("test")
|
SearchResponse searchResponse = client().prepareSearch("test")
|
||||||
.setTypes("type1")
|
.setTypes("type1")
|
||||||
.setQuery(QueryBuilders.matchAllQuery())
|
.setQuery(QueryBuilders.matchAllQuery())
|
||||||
.addSort(SortBuilders.fieldSort("nested1.field1").order(SortOrder.ASC))
|
.addSort(SortBuilders.fieldSort("nested1.field1").order(SortOrder.ASC).setNestedPath("nested1"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 3);
|
assertHitCount(searchResponse, 3);
|
||||||
|
@ -398,7 +398,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
searchResponse = client().prepareSearch("test")
|
searchResponse = client().prepareSearch("test")
|
||||||
.setTypes("type1")
|
.setTypes("type1")
|
||||||
.setQuery(QueryBuilders.matchAllQuery())
|
.setQuery(QueryBuilders.matchAllQuery())
|
||||||
.addSort(SortBuilders.fieldSort("nested1.field1").order(SortOrder.DESC))
|
.addSort(SortBuilders.fieldSort("nested1.field1").order(SortOrder.DESC).setNestedPath("nested1"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 3);
|
assertHitCount(searchResponse, 3);
|
||||||
|
@ -570,7 +570,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
|
|
||||||
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("test").setTypes("type1")
|
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("test").setTypes("type1")
|
||||||
.setQuery(QueryBuilders.matchAllQuery())
|
.setQuery(QueryBuilders.matchAllQuery())
|
||||||
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedFilter(termQuery("nested1.field2", true)).missing(10).order(SortOrder.ASC));
|
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedPath("nested1").setNestedFilter(termQuery("nested1.field2", true)).missing(10).order(SortOrder.ASC));
|
||||||
|
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
searchRequestBuilder.setScroll("10m");
|
searchRequestBuilder.setScroll("10m");
|
||||||
|
@ -587,7 +587,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
assertThat(searchResponse.getHits().hits()[2].sortValues()[0].toString(), equalTo("10"));
|
assertThat(searchResponse.getHits().hits()[2].sortValues()[0].toString(), equalTo("10"));
|
||||||
|
|
||||||
searchRequestBuilder = client().prepareSearch("test").setTypes("type1").setQuery(QueryBuilders.matchAllQuery())
|
searchRequestBuilder = client().prepareSearch("test").setTypes("type1").setQuery(QueryBuilders.matchAllQuery())
|
||||||
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedFilter(termQuery("nested1.field2", true)).missing(10).order(SortOrder.DESC));
|
.addSort(SortBuilders.fieldSort("nested1.field1").setNestedPath("nested1").setNestedFilter(termQuery("nested1.field2", true)).missing(10).order(SortOrder.DESC));
|
||||||
|
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
searchRequestBuilder.setScroll("10m");
|
searchRequestBuilder.setScroll("10m");
|
||||||
|
@ -766,6 +766,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
.setQuery(matchAllQuery())
|
.setQuery(matchAllQuery())
|
||||||
.addSort(
|
.addSort(
|
||||||
SortBuilders.fieldSort("parent.child.child_values")
|
SortBuilders.fieldSort("parent.child.child_values")
|
||||||
|
.setNestedPath("parent.child")
|
||||||
.setNestedFilter(QueryBuilders.termQuery("parent.child.filter", true))
|
.setNestedFilter(QueryBuilders.termQuery("parent.child.filter", true))
|
||||||
.order(SortOrder.ASC)
|
.order(SortOrder.ASC)
|
||||||
)
|
)
|
||||||
|
@ -824,6 +825,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
.setQuery(matchAllQuery())
|
.setQuery(matchAllQuery())
|
||||||
.addSort(
|
.addSort(
|
||||||
SortBuilders.fieldSort("parent.child.child_obj.value")
|
SortBuilders.fieldSort("parent.child.child_obj.value")
|
||||||
|
.setNestedPath("parent.child")
|
||||||
.setNestedFilter(QueryBuilders.termQuery("parent.child.filter", true))
|
.setNestedFilter(QueryBuilders.termQuery("parent.child.filter", true))
|
||||||
.order(SortOrder.ASC)
|
.order(SortOrder.ASC)
|
||||||
)
|
)
|
||||||
|
@ -1080,6 +1082,7 @@ public class SimpleNestedIT extends ESIntegTestCase {
|
||||||
|
|
||||||
SearchResponse searchResponse = client().prepareSearch("test")
|
SearchResponse searchResponse = client().prepareSearch("test")
|
||||||
.addSort(SortBuilders.fieldSort("users.first")
|
.addSort(SortBuilders.fieldSort("users.first")
|
||||||
|
.setNestedPath("users")
|
||||||
.order(SortOrder.ASC))
|
.order(SortOrder.ASC))
|
||||||
.addSort(SortBuilders.fieldSort("users.first")
|
.addSort(SortBuilders.fieldSort("users.first")
|
||||||
.order(SortOrder.ASC)
|
.order(SortOrder.ASC)
|
||||||
|
|
|
@ -551,7 +551,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
|
|
||||||
// Order: Asc
|
// Order: Asc
|
||||||
SearchResponse searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
SearchResponse searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC))
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).setNestedPath("branches"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -563,7 +563,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
|
|
||||||
// Order: Asc, Mode: max
|
// Order: Asc, Mode: max
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max"))
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.ASC).sortMode("max").setNestedPath("branches"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -575,7 +575,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
|
|
||||||
// Order: Desc
|
// Order: Desc
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC))
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).setNestedPath("branches"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -587,7 +587,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
|
|
||||||
// Order: Desc, Mode: min
|
// Order: Desc, Mode: min
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min"))
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).order(SortOrder.DESC).sortMode("min").setNestedPath("branches"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -598,7 +598,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d));
|
assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), closeTo(0d, 10d));
|
||||||
|
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC))
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches"))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -611,7 +611,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(
|
.addSort(
|
||||||
SortBuilders.geoDistanceSort("branches.location").setNestedPath("branches")
|
SortBuilders.geoDistanceSort("branches.location").setNestedPath("branches")
|
||||||
.point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC)
|
.point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.DESC).setNestedPath("branches")
|
||||||
)
|
)
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
|
@ -625,7 +625,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
searchResponse = client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(
|
.addSort(
|
||||||
SortBuilders.geoDistanceSort("branches.location").setNestedFilter(termQuery("branches.name", "brooklyn"))
|
SortBuilders.geoDistanceSort("branches.location").setNestedFilter(termQuery("branches.name", "brooklyn"))
|
||||||
.point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC)
|
.point(40.7143528, -74.0059731).sortMode("avg").order(SortOrder.ASC).setNestedPath("branches")
|
||||||
)
|
)
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
assertHitCount(searchResponse, 4);
|
assertHitCount(searchResponse, 4);
|
||||||
|
@ -637,7 +637,7 @@ public class GeoDistanceIT extends ESIntegTestCase {
|
||||||
assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE));
|
assertThat(((Number) searchResponse.getHits().getAt(3).sortValues()[0]).doubleValue(), equalTo(Double.MAX_VALUE));
|
||||||
|
|
||||||
assertFailures(client().prepareSearch("companies").setQuery(matchAllQuery())
|
assertFailures(client().prepareSearch("companies").setQuery(matchAllQuery())
|
||||||
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("sum")),
|
.addSort(SortBuilders.geoDistanceSort("branches.location").point(40.7143528, -74.0059731).sortMode("sum").setNestedPath("branches")),
|
||||||
RestStatus.BAD_REQUEST,
|
RestStatus.BAD_REQUEST,
|
||||||
containsString("sort_mode [sum] isn't supported for sorting by geo distance"));
|
containsString("sort_mode [sum] isn't supported for sorting by geo distance"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1661,7 +1661,7 @@ public class SimpleSortIT extends ESIntegTestCase {
|
||||||
// We sort on nested field
|
// We sort on nested field
|
||||||
SearchResponse searchResponse = client().prepareSearch()
|
SearchResponse searchResponse = client().prepareSearch()
|
||||||
.setQuery(matchAllQuery())
|
.setQuery(matchAllQuery())
|
||||||
.addSort("nested.foo", SortOrder.DESC)
|
.addSort(SortBuilders.fieldSort("nested.foo").setNestedPath("nested").order(SortOrder.DESC))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
assertNoFailures(searchResponse);
|
assertNoFailures(searchResponse);
|
||||||
SearchHit[] hits = searchResponse.getHits().hits();
|
SearchHit[] hits = searchResponse.getHits().hits();
|
||||||
|
@ -1678,7 +1678,7 @@ public class SimpleSortIT extends ESIntegTestCase {
|
||||||
// We sort on nested sub field
|
// We sort on nested sub field
|
||||||
searchResponse = client().prepareSearch()
|
searchResponse = client().prepareSearch()
|
||||||
.setQuery(matchAllQuery())
|
.setQuery(matchAllQuery())
|
||||||
.addSort("nested.foo.sub", SortOrder.DESC)
|
.addSort(SortBuilders.fieldSort("nested.foo.sub").setNestedPath("nested").order(SortOrder.DESC))
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
assertNoFailures(searchResponse);
|
assertNoFailures(searchResponse);
|
||||||
hits = searchResponse.getHits().hits();
|
hits = searchResponse.getHits().hits();
|
||||||
|
|
|
@ -50,3 +50,9 @@ to using the unlike methods.
|
||||||
|
|
||||||
MoreLikeThisBuilder#addItem has been deprecated in favor to using
|
MoreLikeThisBuilder#addItem has been deprecated in favor to using
|
||||||
MoreLikeThisBuilder#addLikeItem.
|
MoreLikeThisBuilder#addLikeItem.
|
||||||
|
|
||||||
|
=== Nested sorting
|
||||||
|
|
||||||
|
If sorting on field inside a nested object then the `nested_path` should be specified.
|
||||||
|
Before there was an attempt to resolve the nested path automatically, but that was sometimes incorrect.
|
||||||
|
To avoid confusion the `nested_path` should always be specified.
|
|
@ -97,10 +97,8 @@ existing sort options:
|
||||||
|
|
||||||
===== Nested sorting example
|
===== Nested sorting example
|
||||||
|
|
||||||
In the below example `offer` is a field of type `nested`. Because
|
In the below example `offer` is a field of type `nested`.
|
||||||
`offer` is the closest inherited nested field, it is picked as
|
The `nested_path` needs to be specified other elasticsearch doesn't on what nested level sort values need to be captured.
|
||||||
`nested_path`. Only the inner objects that have color blue will
|
|
||||||
participate in sorting.
|
|
||||||
|
|
||||||
[source,js]
|
[source,js]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
@ -113,6 +111,7 @@ curl -XPOST 'localhost:9200/_search' -d '{
|
||||||
"offer.price" : {
|
"offer.price" : {
|
||||||
"mode" : "avg",
|
"mode" : "avg",
|
||||||
"order" : "asc",
|
"order" : "asc",
|
||||||
|
"nested_path" : "offer",
|
||||||
"nested_filter" : {
|
"nested_filter" : {
|
||||||
"term" : { "offer.color" : "blue" }
|
"term" : { "offer.color" : "blue" }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue