Skip to content

Commit e0daa6e

Browse files
Luci-MGshiv0408
authored andcommitted
FIX: UOE While building Exists query for nested search_as_you_type field (opensearch-project#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 <gm13@iitbbs.ac.in> Signed-off-by: Shivansh Arora <hishiv@amazon.com>
1 parent ce47d47 commit e0daa6e

File tree

4 files changed

+36
-0
lines changed

4 files changed

+36
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
9898
- [Bug] Check phase name before SearchRequestOperationsListener onPhaseStart ([#12035](https://github.com/opensearch-project/OpenSearch/pull/12035))
9999
- Fix Span operation names generated from RestActions ([#12005](https://github.com/opensearch-project/OpenSearch/pull/12005))
100100
- Fix error in RemoteSegmentStoreDirectory when debug logging is enabled ([#12328](https://github.com/opensearch-project/OpenSearch/pull/12328))
101+
- Fix UOE While building Exists query for nested search_as_you_type field ([#12048](https://github.com/opensearch-project/OpenSearch/pull/12048))
101102

102103
### Security
103104

modules/mapper-extras/src/test/java/org/opensearch/index/mapper/SearchAsYouTypeFieldMapperTests.java

+27
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.apache.lucene.search.DisjunctionMaxQuery;
4848
import org.apache.lucene.search.MatchNoDocsQuery;
4949
import org.apache.lucene.search.MultiPhraseQuery;
50+
import org.apache.lucene.search.NormsFieldExistsQuery;
5051
import org.apache.lucene.search.Query;
5152
import org.apache.lucene.search.SynonymQuery;
5253
import org.apache.lucene.search.TermQuery;
@@ -68,6 +69,7 @@
6869
import org.opensearch.index.query.MatchPhraseQueryBuilder;
6970
import org.opensearch.index.query.MultiMatchQueryBuilder;
7071
import org.opensearch.index.query.QueryShardContext;
72+
import org.opensearch.index.query.QueryStringQueryBuilder;
7173
import org.opensearch.plugins.Plugin;
7274

7375
import java.io.IOException;
@@ -541,6 +543,31 @@ public void testMatchPhrase() throws IOException {
541543
}
542544
}
543545

546+
public void testNestedExistsQuery() throws IOException {
547+
MapperService mapperService = createMapperService(mapping(b -> {
548+
b.startObject("field");
549+
{
550+
b.field("type", "object");
551+
b.startObject("properties");
552+
{
553+
b.startObject("nested_field");
554+
{
555+
b.field("type", "search_as_you_type");
556+
}
557+
b.endObject();
558+
}
559+
b.endObject();
560+
}
561+
b.endObject();
562+
}));
563+
QueryShardContext queryShardContext = createQueryShardContext(mapperService);
564+
Query actual = new QueryStringQueryBuilder("field:*").toQuery(queryShardContext);
565+
Query expected = new ConstantScoreQuery(
566+
new BooleanQuery.Builder().add(new NormsFieldExistsQuery("field.nested_field"), BooleanClause.Occur.SHOULD).build()
567+
);
568+
assertEquals(expected, actual);
569+
}
570+
544571
private static BooleanQuery buildBoolPrefixQuery(String shingleFieldName, String prefixFieldName, List<String> terms) {
545572
final BooleanQuery.Builder builder = new BooleanQuery.Builder();
546573
for (int i = 0; i < terms.size() - 1; i++) {

server/src/main/java/org/opensearch/index/query/ExistsQueryBuilder.java

+5
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ private static Query newObjectFieldExistsQuery(QueryShardContext context, String
201201
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
202202
Collection<String> fields = context.simpleMatchToIndexNames(objField + ".*");
203203
for (String field : fields) {
204+
int dotPos = field.lastIndexOf('.');
205+
if (dotPos > 0 && field.charAt(dotPos + 1) == '_') {
206+
// This is a subfield (e.g. prefix) of a complex field type. Skip it.
207+
continue;
208+
}
204209
Query existsQuery = context.getMapperService().fieldType(field).existsQuery(context);
205210
booleanQuery.add(existsQuery, Occur.SHOULD);
206211
}

test/framework/src/main/java/org/opensearch/index/mapper/MapperServiceTestCase.java

+3
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ protected QueryShardContext createQueryShardContext(MapperService mapperService)
247247
when(queryShardContext.getSearchQuoteAnalyzer(any())).thenCallRealMethod();
248248
when(queryShardContext.getSearchAnalyzer(any())).thenCallRealMethod();
249249
when(queryShardContext.getIndexSettings()).thenReturn(mapperService.getIndexSettings());
250+
when(queryShardContext.getObjectMapper(anyString())).thenAnswer(
251+
inv -> mapperService.getObjectMapper(inv.getArguments()[0].toString())
252+
);
250253
when(queryShardContext.simpleMatchToIndexNames(any())).thenAnswer(
251254
inv -> mapperService.simpleMatchToFullName(inv.getArguments()[0].toString())
252255
);

0 commit comments

Comments
 (0)