Skip to content

Commit 987f4fa

Browse files
bugmakerrrrrrmch2
andauthored
Fix object field exists query (#17843)
* Fix object field exists query Signed-off-by: panguixin <panguixin@bytedance.com> * catch uoe Signed-off-by: panguixin <panguixin@bytedance.com> * changelog Signed-off-by: panguixin <panguixin@bytedance.com> --------- Signed-off-by: panguixin <panguixin@bytedance.com> Signed-off-by: Marc Handalian <marc.handalian@gmail.com> Co-authored-by: Marc Handalian <marc.handalian@gmail.com>
1 parent 00abaac commit 987f4fa

File tree

5 files changed

+52
-8
lines changed

5 files changed

+52
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3131
- Fix simultaneously creating a snapshot and updating the repository can potentially trigger an infinite loop ([#17532](https://github.com/opensearch-project/OpenSearch/pull/17532))
3232
- Remove package org.opensearch.transport.grpc and replace with org.opensearch.plugin.transport.grpc ([#18031](https://github.com/opensearch-project/OpenSearch/pull/18031))
3333
- Fix the native plugin installation error cause by the pgp public key change ([#18147](https://github.com/opensearch-project/OpenSearch/pull/18147))
34+
- Fix object field exists query ([#17843](https://github.com/opensearch-project/OpenSearch/pull/17843))
3435

3536
### Security
3637

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,10 @@ public void testNestedExistsQuery() throws IOException {
577577
QueryShardContext queryShardContext = createQueryShardContext(mapperService);
578578
Query actual = new QueryStringQueryBuilder("field:*").toQuery(queryShardContext);
579579
Query expected = new ConstantScoreQuery(
580-
new BooleanQuery.Builder().add(new FieldExistsQuery("field.nested_field"), BooleanClause.Occur.SHOULD).build()
580+
new BooleanQuery.Builder().add(new FieldExistsQuery("field.nested_field"), BooleanClause.Occur.SHOULD)
581+
.add(new FieldExistsQuery("field.nested_field._2gram"), BooleanClause.Occur.SHOULD)
582+
.add(new FieldExistsQuery("field.nested_field._3gram"), BooleanClause.Occur.SHOULD)
583+
.build()
581584
);
582585
assertEquals(expected, actual);
583586
}

server/src/main/java/org/opensearch/index/mapper/DerivedFieldType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ public Query geoShapeQuery(Geometry shape, String fieldName, ShapeRelation relat
477477

478478
@Override
479479
public Query existsQuery(QueryShardContext context) {
480-
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] does not support exist queries");
480+
throw new UnsupportedOperationException("Field [" + name() + "] of type [" + typeName() + "] does not support exist queries");
481481
}
482482

483483
@Override

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,13 @@ private static Query newObjectFieldExistsQuery(QueryShardContext context, String
202202
BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
203203
Collection<String> fields = context.simpleMatchToIndexNames(objField + ".*");
204204
for (String field : fields) {
205-
int dotPos = field.lastIndexOf('.');
206-
if (dotPos > 0 && field.charAt(dotPos + 1) == '_') {
207-
// This is a subfield (e.g. prefix) of a complex field type. Skip it.
208-
continue;
205+
try {
206+
Query existsQuery = context.getMapperService().fieldType(field).existsQuery(context);
207+
booleanQuery.add(existsQuery, Occur.SHOULD);
208+
} catch (UnsupportedOperationException e) {
209+
// ignore some subfields which not support exists query
210+
// if none of the subfields support the exists query, this is equivalent to MatchNoDocsQuery
209211
}
210-
Query existsQuery = context.getMapperService().fieldType(field).existsQuery(context);
211-
booleanQuery.add(existsQuery, Occur.SHOULD);
212212
}
213213
return new ConstantScoreQuery(booleanQuery.build());
214214
}

server/src/test/java/org/opensearch/index/query/ExistsQueryBuilderTests.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
import org.apache.lucene.search.MatchNoDocsQuery;
4040
import org.apache.lucene.search.Query;
4141
import org.apache.lucene.search.TermQuery;
42+
import org.opensearch.common.compress.CompressedXContent;
43+
import org.opensearch.core.xcontent.XContentBuilder;
44+
import org.opensearch.index.mapper.MapperService;
4245
import org.opensearch.test.AbstractQueryTestCase;
4346

4447
import java.io.IOException;
@@ -47,10 +50,35 @@
4750
import java.util.List;
4851
import java.util.stream.Collectors;
4952

53+
import static org.opensearch.common.xcontent.XContentFactory.jsonBuilder;
5054
import static org.hamcrest.CoreMatchers.equalTo;
5155
import static org.hamcrest.CoreMatchers.instanceOf;
5256

5357
public class ExistsQueryBuilderTests extends AbstractQueryTestCase<ExistsQueryBuilder> {
58+
59+
@Override
60+
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
61+
XContentBuilder mapping = jsonBuilder().startObject()
62+
.startObject("_doc")
63+
.startObject("properties")
64+
.startObject("raw.keyword")
65+
.field("type", "keyword")
66+
.endObject()
67+
.endObject()
68+
.startObject("derived")
69+
.startObject("raw.derived_keyword")
70+
.field("type", "keyword")
71+
.startObject("script")
72+
.field("source", "emit(doc['raw.keyword'].value)")
73+
.endObject()
74+
.endObject()
75+
.endObject()
76+
.endObject()
77+
.endObject();
78+
79+
mapperService.merge("_doc", new CompressedXContent(mapping.toString()), MapperService.MergeReason.MAPPING_UPDATE);
80+
}
81+
5482
@Override
5583
protected ExistsQueryBuilder doCreateTestQueryBuilder() {
5684
String fieldPattern;
@@ -144,4 +172,16 @@ public void testFromJson() throws IOException {
144172
assertEquals(json, 42.0, parsed.boost(), 0.0001);
145173
assertEquals(json, "user", parsed.fieldName());
146174
}
175+
176+
public void testObjectFieldWithDerivedSubField() throws IOException {
177+
QueryShardContext shardContext = createShardContext();
178+
final ExistsQueryBuilder queryBuilder1 = new ExistsQueryBuilder("raw.derived_keyword");
179+
expectThrows(UnsupportedOperationException.class, () -> queryBuilder1.toQuery(shardContext));
180+
final ExistsQueryBuilder queryBuilder2 = new ExistsQueryBuilder("raw");
181+
Query actual = queryBuilder2.toQuery(shardContext);
182+
Query expected = new ConstantScoreQuery(
183+
new BooleanQuery.Builder().add(new FieldExistsQuery("raw.keyword"), BooleanClause.Occur.SHOULD).build()
184+
);
185+
assertEquals(expected, actual);
186+
}
147187
}

0 commit comments

Comments
 (0)