Skip to content

Commit c00df89

Browse files
committed
[GRPC][Full-text] Match Phrase, Multi-match queries
Signed-off-by: Karen X <[email protected]>
1 parent fef4f49 commit c00df89

11 files changed

+1309
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2929
- Add all-active ingestion as docrep equivalent in pull-based ingestion ([#19316](https://github.com/opensearch-project/OpenSearch/pull/19316))
3030
- Adding logic for histogram aggregation using skiplist ([#19130](https://github.com/opensearch-project/OpenSearch/pull/19130))
3131
- Add skip_list param for date, scaled float and token count fields ([#19142](https://github.com/opensearch-project/OpenSearch/pull/19142))
32+
- Implement GRPC MatchPhrase, MultiMatch queries ([#19449](https://github.com/opensearch-project/OpenSearch/pull/19449))
3233

3334
### Changed
3435
- Refactor `if-else` chains to use `Java 17 pattern matching switch expressions`(([#18965](https://github.com/opensearch-project/OpenSearch/pull/18965))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
package org.opensearch.transport.grpc.proto.request.search.query;
9+
10+
import org.opensearch.index.query.QueryBuilder;
11+
import org.opensearch.protobufs.QueryContainer;
12+
import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverter;
13+
14+
/**
15+
* Converter for MatchPhrase queries.
16+
* This class implements the QueryBuilderProtoConverter interface to provide MatchPhrase query support
17+
* for the gRPC transport module.
18+
*/
19+
public class MatchPhraseQueryBuilderProtoConverter implements QueryBuilderProtoConverter {
20+
21+
/**
22+
* Constructs a new MatchPhraseQueryBuilderProtoConverter.
23+
*/
24+
public MatchPhraseQueryBuilderProtoConverter() {
25+
// Default constructor
26+
}
27+
28+
@Override
29+
public QueryContainer.QueryContainerCase getHandledQueryCase() {
30+
return QueryContainer.QueryContainerCase.MATCH_PHRASE;
31+
}
32+
33+
@Override
34+
public QueryBuilder fromProto(QueryContainer queryContainer) {
35+
if (queryContainer == null || !queryContainer.hasMatchPhrase()) {
36+
throw new IllegalArgumentException("QueryContainer does not contain a MatchPhrase query");
37+
}
38+
39+
return MatchPhraseQueryBuilderProtoUtils.fromProto(queryContainer.getMatchPhrase());
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.transport.grpc.proto.request.search.query;
10+
11+
import org.opensearch.index.query.AbstractQueryBuilder;
12+
import org.opensearch.index.query.MatchPhraseQueryBuilder;
13+
import org.opensearch.index.search.MatchQuery;
14+
import org.opensearch.protobufs.MatchPhraseQuery;
15+
import org.opensearch.protobufs.ZeroTermsQuery;
16+
17+
/**
18+
* Utility class for converting Protocol Buffer MatchPhraseQuery objects to OpenSearch MatchPhraseQueryBuilder instances.
19+
* This class handles the detailed conversion logic, including parsing of all MatchPhraseQuery parameters,
20+
* analyzer settings, slop configuration, zero terms query behavior, boost values, and query names.
21+
*
22+
* @opensearch.internal
23+
*/
24+
public class MatchPhraseQueryBuilderProtoUtils {
25+
/**
26+
* Private constructor to prevent instantiation of utility class.
27+
*/
28+
private MatchPhraseQueryBuilderProtoUtils() {
29+
// Utility class
30+
}
31+
32+
/**
33+
* Converts a Protocol Buffer MatchPhraseQuery to a MatchPhraseQueryBuilder.
34+
* This method extracts all relevant parameters from the protobuf representation and
35+
* creates a properly configured MatchPhraseQueryBuilder with the appropriate field name,
36+
* query value, analyzer, slop, zero terms query behavior, boost, and query name.
37+
*
38+
* @param matchPhraseQueryProto The Protocol Buffer MatchPhraseQuery object
39+
* @return A properly configured MatchPhraseQueryBuilder
40+
* @throws IllegalArgumentException if the MatchPhraseQuery is null or if required fields are missing
41+
*/
42+
public static MatchPhraseQueryBuilder fromProto(MatchPhraseQuery matchPhraseQueryProto) {
43+
if (matchPhraseQueryProto == null) {
44+
throw new IllegalArgumentException("MatchPhraseQuery cannot be null");
45+
}
46+
47+
String fieldName = matchPhraseQueryProto.getField();
48+
if (fieldName.isEmpty()) {
49+
throw new IllegalArgumentException("Field name cannot be null or empty for match phrase query");
50+
}
51+
52+
String value = matchPhraseQueryProto.getQuery();
53+
if (value.isEmpty()) {
54+
throw new IllegalArgumentException("Query value cannot be null or empty for match phrase query");
55+
}
56+
57+
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
58+
String analyzer = null;
59+
int slop = MatchQuery.DEFAULT_PHRASE_SLOP;
60+
MatchQuery.ZeroTermsQuery zeroTermsQuery = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
61+
String queryName = null;
62+
if (matchPhraseQueryProto.hasAnalyzer()) {
63+
analyzer = matchPhraseQueryProto.getAnalyzer();
64+
}
65+
66+
if (matchPhraseQueryProto.hasSlop()) {
67+
int slopValue = matchPhraseQueryProto.getSlop();
68+
if (slopValue < 0) {
69+
throw new IllegalArgumentException("No negative slop allowed.");
70+
}
71+
slop = slopValue;
72+
}
73+
74+
if (matchPhraseQueryProto.hasZeroTermsQuery()) {
75+
ZeroTermsQuery zeroTermsQueryProto = matchPhraseQueryProto.getZeroTermsQuery();
76+
MatchQuery.ZeroTermsQuery parsedZeroTermsQuery = parseZeroTermsQuery(zeroTermsQueryProto);
77+
if (parsedZeroTermsQuery != null) {
78+
zeroTermsQuery = parsedZeroTermsQuery;
79+
}
80+
}
81+
82+
if (matchPhraseQueryProto.hasBoost()) {
83+
boost = matchPhraseQueryProto.getBoost();
84+
}
85+
86+
if (matchPhraseQueryProto.hasXName()) {
87+
queryName = matchPhraseQueryProto.getXName();
88+
}
89+
90+
MatchPhraseQueryBuilder matchQuery = new MatchPhraseQueryBuilder(fieldName, value);
91+
matchQuery.analyzer(analyzer);
92+
matchQuery.slop(slop);
93+
matchQuery.zeroTermsQuery(zeroTermsQuery);
94+
matchQuery.queryName(queryName);
95+
matchQuery.boost(boost);
96+
97+
return matchQuery;
98+
}
99+
100+
/**
101+
* Parses ZeroTermsQuery enum to MatchQuery.ZeroTermsQuery.
102+
*
103+
* @param zeroTermsQueryProto The ZeroTermsQuery enum value
104+
* @return The corresponding MatchQuery.ZeroTermsQuery, or null if unsupported
105+
*/
106+
private static MatchQuery.ZeroTermsQuery parseZeroTermsQuery(ZeroTermsQuery zeroTermsQueryProto) {
107+
if (zeroTermsQueryProto == null) {
108+
return null;
109+
}
110+
111+
switch (zeroTermsQueryProto) {
112+
case ZERO_TERMS_QUERY_ALL:
113+
return MatchQuery.ZeroTermsQuery.ALL;
114+
case ZERO_TERMS_QUERY_NONE:
115+
return MatchQuery.ZeroTermsQuery.NONE;
116+
default:
117+
return null;
118+
}
119+
}
120+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
package org.opensearch.transport.grpc.proto.request.search.query;
9+
10+
import org.opensearch.index.query.QueryBuilder;
11+
import org.opensearch.protobufs.QueryContainer;
12+
import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverter;
13+
14+
/**
15+
* Converter for MultiMatch queries.
16+
* This class implements the QueryBuilderProtoConverter interface to provide MultiMatch query support
17+
* for the gRPC transport module.
18+
*/
19+
public class MultiMatchQueryBuilderProtoConverter implements QueryBuilderProtoConverter {
20+
21+
/**
22+
* Constructs a new MultiMatchQueryBuilderProtoConverter.
23+
*/
24+
public MultiMatchQueryBuilderProtoConverter() {
25+
// Default constructor
26+
}
27+
28+
@Override
29+
public QueryContainer.QueryContainerCase getHandledQueryCase() {
30+
return QueryContainer.QueryContainerCase.MULTI_MATCH;
31+
}
32+
33+
@Override
34+
public QueryBuilder fromProto(QueryContainer queryContainer) {
35+
if (queryContainer == null || !queryContainer.hasMultiMatch()) {
36+
throw new IllegalArgumentException("QueryContainer does not contain a MultiMatch query");
37+
}
38+
39+
return MultiMatchQueryBuilderProtoUtils.fromProto(queryContainer.getMultiMatch());
40+
}
41+
}

0 commit comments

Comments
 (0)