Skip to content

Commit

Permalink
FIX: UOE While building Exists query for nested search_as_you_type fi…
Browse files Browse the repository at this point in the history
…eld (#12048)

The "exists" query on an object field would fail when a "search_as_you_type" field is nested under that object.

It would also fail for a text field with prefixes enabled nested under the object, or any other field with a 
"hidden" subfield.

---------

Signed-off-by: Mrudhul Guda <[email protected]>
  • Loading branch information
Luci-MG committed Apr 1, 2024
1 parent 1ec49bd commit 37569ba
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Bug] Check phase name before SearchRequestOperationsListener onPhaseStart ([#12035](https://github.com/opensearch-project/OpenSearch/pull/12035))
- Fix Span operation names generated from RestActions ([#12005](https://github.com/opensearch-project/OpenSearch/pull/12005))
- Fix error in RemoteSegmentStoreDirectory when debug logging is enabled ([#12328](https://github.com/opensearch-project/OpenSearch/pull/12328))
- Fix UOE While building Exists query for nested search_as_you_type field ([#12048](https://github.com/opensearch-project/OpenSearch/pull/12048))

### Security

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.apache.lucene.search.DisjunctionMaxQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.NormsFieldExistsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SynonymQuery;
import org.apache.lucene.search.TermQuery;
Expand All @@ -68,6 +69,7 @@
import org.opensearch.index.query.MatchPhraseQueryBuilder;
import org.opensearch.index.query.MultiMatchQueryBuilder;
import org.opensearch.index.query.QueryShardContext;
import org.opensearch.index.query.QueryStringQueryBuilder;
import org.opensearch.plugins.Plugin;

import java.io.IOException;
Expand Down Expand Up @@ -541,6 +543,31 @@ public void testMatchPhrase() throws IOException {
}
}

public void testNestedExistsQuery() throws IOException {
MapperService mapperService = createMapperService(mapping(b -> {
b.startObject("field");
{
b.field("type", "object");
b.startObject("properties");
{
b.startObject("nested_field");
{
b.field("type", "search_as_you_type");
}
b.endObject();
}
b.endObject();
}
b.endObject();
}));
QueryShardContext queryShardContext = createQueryShardContext(mapperService);
Query actual = new QueryStringQueryBuilder("field:*").toQuery(queryShardContext);
Query expected = new ConstantScoreQuery(
new BooleanQuery.Builder().add(new NormsFieldExistsQuery("field.nested_field"), BooleanClause.Occur.SHOULD).build()
);
assertEquals(expected, actual);
}

private static BooleanQuery buildBoolPrefixQuery(String shingleFieldName, String prefixFieldName, List<String> terms) {
final BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (int i = 0; i < terms.size() - 1; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ private static Query newObjectFieldExistsQuery(QueryShardContext context, String
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
Collection<String> fields = context.simpleMatchToIndexNames(objField + ".*");
for (String field : fields) {
int dotPos = field.lastIndexOf('.');
if (dotPos > 0 && field.charAt(dotPos + 1) == '_') {
// This is a subfield (e.g. prefix) of a complex field type. Skip it.
continue;
}
Query existsQuery = context.getMapperService().fieldType(field).existsQuery(context);
booleanQuery.add(existsQuery, Occur.SHOULD);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ protected QueryShardContext createQueryShardContext(MapperService mapperService)
when(queryShardContext.getSearchQuoteAnalyzer(any())).thenCallRealMethod();
when(queryShardContext.getSearchAnalyzer(any())).thenCallRealMethod();
when(queryShardContext.getIndexSettings()).thenReturn(mapperService.getIndexSettings());
when(queryShardContext.getObjectMapper(anyString())).thenAnswer(
inv -> mapperService.getObjectMapper(inv.getArguments()[0].toString())
);
when(queryShardContext.simpleMatchToIndexNames(any())).thenAnswer(
inv -> mapperService.simpleMatchToFullName(inv.getArguments()[0].toString())
);
Expand Down

0 comments on commit 37569ba

Please sign in to comment.