Skip to content

Commit bfdf019

Browse files
authored
Add filter function for AbstractQueryBuilder, BoolQueryBuilder, ConstantScoreQueryBuilder. (#17409) (#17409)
* The filter function will combine a filter with the query builder. If the query builder itself has a filter we will combine the filter and return the query builder itself. If no we will use a bool query builder to combine the query builder and the filter and then return the bool query builder. Signed-off-by: Chloe Gao <[email protected]>
1 parent 968eafb commit bfdf019

File tree

10 files changed

+123
-6
lines changed

10 files changed

+123
-6
lines changed

CHANGELOG-3.0.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2121
- Add execution_hint to cardinality aggregator request (#[17312](https://github.com/opensearch-project/OpenSearch/pull/17312))
2222
- Arrow Flight RPC plugin with Flight server bootstrap logic and client for internode communication ([#16962](https://github.com/opensearch-project/OpenSearch/pull/16962))
2323
- Added offset management for the pull-based Ingestion ([#17354](https://github.com/opensearch-project/OpenSearch/pull/17354))
24+
- Add filter function for AbstractQueryBuilder, BoolQueryBuilder, ConstantScoreQueryBuilder([#17409](https://github.com/opensearch-project/OpenSearch/pull/17409))
2425

2526
### Dependencies
2627
- Update Apache Lucene to 10.1.0 ([#16366](https://github.com/opensearch-project/OpenSearch/pull/16366))

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,30 @@ protected AbstractQueryBuilder(StreamInput in) throws IOException {
8686
queryName = in.readOptionalString();
8787
}
8888

89+
/**
90+
* Check the input parameters of filter function.
91+
* @param filter filter to combine with current query builder
92+
* @return true if parameters are valid. Returns false when the filter is null.
93+
*/
94+
public static boolean validateFilterParams(QueryBuilder filter) {
95+
return filter != null;
96+
}
97+
98+
/**
99+
* Combine filter with current query builder
100+
* @param filter filter to combine with current query builder
101+
* @return query builder with filter combined
102+
*/
103+
public QueryBuilder filter(QueryBuilder filter) {
104+
if (validateFilterParams(filter) == false) {
105+
return this;
106+
}
107+
final BoolQueryBuilder modifiedQB = new BoolQueryBuilder();
108+
modifiedQB.must(this);
109+
modifiedQB.filter(filter);
110+
return modifiedQB;
111+
}
112+
89113
@Override
90114
public final void writeTo(StreamOutput out) throws IOException {
91115
out.writeFloat(boost);

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,15 @@ public List<QueryBuilder> must() {
135135

136136
/**
137137
* Adds a query that <b>must</b> appear in the matching documents but will
138-
* not contribute to scoring. No {@code null} value allowed.
138+
* not contribute to scoring. If null value passed, then do nothing and return.
139+
* @param filter the filter to add to the current ConstantScoreQuery
140+
* @return query builder with filter combined
139141
*/
140-
public BoolQueryBuilder filter(QueryBuilder queryBuilder) {
141-
if (queryBuilder == null) {
142-
throw new IllegalArgumentException("inner bool query clause cannot be null");
142+
public BoolQueryBuilder filter(QueryBuilder filter) {
143+
if (validateFilterParams(filter) == false) {
144+
return this;
143145
}
144-
filterClauses.add(queryBuilder);
146+
filterClauses.add(filter);
145147
return this;
146148
}
147149

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
101101
builder.endObject();
102102
}
103103

104+
/**
105+
* Adds a filter to the current ConstantScoreQuery.
106+
* @param filter the filter to add to the current ConstantScoreQuery
107+
* @return query builder with filter combined
108+
*/
109+
public ConstantScoreQueryBuilder filter(QueryBuilder filter) {
110+
if (validateFilterParams(filter) == false) {
111+
return this;
112+
}
113+
QueryBuilder filteredFilterBuilder = filterBuilder.filter(filter);
114+
if (filteredFilterBuilder != filterBuilder) {
115+
return new ConstantScoreQueryBuilder(filteredFilterBuilder);
116+
}
117+
return this;
118+
}
119+
104120
public static ConstantScoreQueryBuilder fromXContent(XContentParser parser) throws IOException {
105121
QueryBuilder query = null;
106122
boolean queryFound = false;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@
4747
@PublicApi(since = "1.0.0")
4848
public interface QueryBuilder extends NamedWriteable, ToXContentObject, Rewriteable<QueryBuilder> {
4949

50+
/**
51+
* This function combines a filter with a query builder. If the query builder itself has
52+
* a filter we will combine the filter and return the query builder itself.
53+
* If not we will use a bool query builder to combine the query builder and
54+
* the filter and then return the bool query builder.
55+
* If the filter is null we simply return the query builder without any operation.
56+
*
57+
* @param filter The null filter to be added to the existing filter.
58+
* @return A QueryBuilder with the filter added to the existing filter.
59+
*/
60+
QueryBuilder filter(QueryBuilder filter);
61+
5062
/**
5163
* Converts this QueryBuilder to a lucene {@link Query}.
5264
* Returns {@code null} if this query should be ignored in the context of

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,11 @@ public Query toQuery(QueryShardContext context) throws IOException {
375375
throw new UnsupportedOperationException();
376376
}
377377

378+
@Override
379+
public QueryBuilder filter(QueryBuilder filter) {
380+
throw new UnsupportedOperationException("You can't add a filter to a SpanGapQueryBuilder");
381+
}
382+
378383
@Override
379384
public String queryName() {
380385
throw new UnsupportedOperationException();

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ public void testIllegalArguments() {
178178
BoolQueryBuilder booleanQuery = new BoolQueryBuilder();
179179
expectThrows(IllegalArgumentException.class, () -> booleanQuery.must(null));
180180
expectThrows(IllegalArgumentException.class, () -> booleanQuery.mustNot(null));
181-
expectThrows(IllegalArgumentException.class, () -> booleanQuery.filter(null));
182181
expectThrows(IllegalArgumentException.class, () -> booleanQuery.should(null));
183182
}
184183

@@ -326,6 +325,23 @@ public void testFilterNull() throws IOException {
326325
assertTrue(builder.filter().isEmpty());
327326
}
328327

328+
/**
329+
* Check if a filter can be applied to the BoolQuery
330+
* @throws IOException
331+
*/
332+
public void testFilter() throws IOException {
333+
// Test for non null filter
334+
String query = "{\"bool\" : {\"filter\" : null } }";
335+
QueryBuilder filter = QueryBuilders.matchAllQuery();
336+
BoolQueryBuilder builder = (BoolQueryBuilder) parseQuery(query);
337+
assertFalse(builder.filter(filter).filter().isEmpty());
338+
assertEquals(builder.filter(filter).filter().get(0), filter);
339+
340+
// Test for null filter case
341+
builder = (BoolQueryBuilder) parseQuery(query);
342+
assertTrue(builder.filter(null).filter().isEmpty());
343+
}
344+
329345
/**
330346
* test that unknown query names in the clauses throw an error
331347
*/

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,21 @@ public void testVisit() {
143143

144144
assertEquals(2, visitorQueries.size());
145145
}
146+
147+
public void testFilter() {
148+
// Test for non null filter
149+
BoolQueryBuilder filterBuilder = new BoolQueryBuilder();
150+
ConstantScoreQueryBuilder constantScoreQueryBuilder = new ConstantScoreQueryBuilder(filterBuilder);
151+
QueryBuilder filter = QueryBuilders.matchAllQuery();
152+
constantScoreQueryBuilder.filter(filter);
153+
assertEquals(1, filterBuilder.filter().size());
154+
assertEquals(filter, filterBuilder.filter().get(0));
155+
156+
// Test for null filter
157+
filterBuilder = new BoolQueryBuilder();
158+
constantScoreQueryBuilder = new ConstantScoreQueryBuilder(filterBuilder);
159+
constantScoreQueryBuilder.filter(null);
160+
assertEquals(0, filterBuilder.filter().size());
161+
162+
}
146163
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ public void writeTo(StreamOutput out) throws IOException {
182182
public String fieldName() {
183183
return "foo";
184184
}
185+
186+
@Override
187+
public QueryBuilder filter(QueryBuilder filter) {
188+
return this;
189+
}
185190
}
186191

187192
@Override

test/framework/src/main/java/org/opensearch/test/AbstractQueryTestCase.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@
6363
import org.opensearch.core.xcontent.XContentParseException;
6464
import org.opensearch.core.xcontent.XContentParser;
6565
import org.opensearch.index.query.AbstractQueryBuilder;
66+
import org.opensearch.index.query.BoolQueryBuilder;
6667
import org.opensearch.index.query.QueryBuilder;
68+
import org.opensearch.index.query.QueryBuilders;
6769
import org.opensearch.index.query.QueryRewriteContext;
6870
import org.opensearch.index.query.QueryShardContext;
6971
import org.opensearch.index.query.Rewriteable;
@@ -868,4 +870,21 @@ public void testCacheability() throws IOException {
868870
assertTrue("query should be cacheable: " + queryBuilder.toString(), context.isCacheable());
869871
}
870872

873+
/**
874+
* Check if a filter can be applied to the abstract query builder.
875+
* @throws UnsupportedOperationException
876+
*/
877+
public void testFilter() throws IOException {
878+
QB queryBuilder = createTestQueryBuilder();
879+
QueryBuilder filter = QueryBuilders.matchAllQuery();
880+
// Test for Null Filter case
881+
QueryBuilder returnedQuerybuilder = queryBuilder.filter(null);
882+
assertEquals(queryBuilder, returnedQuerybuilder);
883+
884+
// Test for non null filter
885+
returnedQuerybuilder = queryBuilder.filter(filter);
886+
assertTrue(returnedQuerybuilder instanceof BoolQueryBuilder);
887+
assertTrue(((BoolQueryBuilder) returnedQuerybuilder).filter().size() == 1);
888+
assertEquals(filter, ((BoolQueryBuilder) returnedQuerybuilder).filter().get(0));
889+
}
871890
}

0 commit comments

Comments
 (0)