Skip to content

Commit ada899d

Browse files
committed
optimize the canMatch phase on the data node
Signed-off-by: panguixin <[email protected]>
1 parent f8e8865 commit ada899d

File tree

3 files changed

+45
-27
lines changed

3 files changed

+45
-27
lines changed

server/src/main/java/org/opensearch/search/SearchService.java

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@
8383
import org.opensearch.index.query.InnerHitContextBuilder;
8484
import org.opensearch.index.query.MatchAllQueryBuilder;
8585
import org.opensearch.index.query.MatchNoneQueryBuilder;
86-
import org.opensearch.index.query.QueryBuilder;
8786
import org.opensearch.index.query.QueryRewriteContext;
8887
import org.opensearch.index.query.QueryShardContext;
8988
import org.opensearch.index.query.Rewriteable;
@@ -1597,8 +1596,7 @@ public CanMatchResponse canMatch(ShardSearchRequest request) throws IOException
15971596
private CanMatchResponse canMatch(ShardSearchRequest request, boolean checkRefreshPending) throws IOException {
15981597
assert request.searchType() == SearchType.QUERY_THEN_FETCH : "unexpected search type: " + request.searchType();
15991598
final ReaderContext readerContext = request.readerId() != null ? findReaderContext(request.readerId(), request) : null;
1600-
final Releasable markAsUsed = readerContext != null ? readerContext.markAsUsed(getKeepAlive(request)) : () -> {};
1601-
try (Releasable ignored = markAsUsed) {
1599+
try (Releasable ignored = readerContext != null ? readerContext.markAsUsed(getKeepAlive(request)) : () -> {}) {
16021600
final IndexService indexService;
16031601
final Engine.Searcher canMatchSearcher;
16041602
final boolean hasRefreshPending;
@@ -1621,22 +1619,34 @@ private CanMatchResponse canMatch(ShardSearchRequest request, boolean checkRefre
16211619
request.getClusterAlias()
16221620
);
16231621
Rewriteable.rewrite(request.getRewriteable(), context, false);
1622+
1623+
if (hasRefreshPending) {
1624+
final FieldSortBuilder sortBuilder = FieldSortBuilder.getPrimaryFieldSortOrNull(request.source());
1625+
final MinAndMax<?> minMax = sortBuilder != null ? FieldSortBuilder.getMinMaxOrNull(context, sortBuilder) : null;
1626+
return new CanMatchResponse(true, minMax);
1627+
}
1628+
16241629
final boolean aliasFilterCanMatch = request.getAliasFilter().getQueryBuilder() instanceof MatchNoneQueryBuilder == false;
1625-
FieldSortBuilder sortBuilder = FieldSortBuilder.getPrimaryFieldSortOrNull(request.source());
1626-
MinAndMax<?> minMax = sortBuilder != null ? FieldSortBuilder.getMinMaxOrNull(context, sortBuilder) : null;
1627-
boolean canMatch;
1628-
if (canRewriteToMatchNone(request.source())) {
1629-
QueryBuilder queryBuilder = request.source().query();
1630-
canMatch = aliasFilterCanMatch && queryBuilder instanceof MatchNoneQueryBuilder == false;
1631-
} else {
1632-
// null query means match_all
1633-
canMatch = aliasFilterCanMatch;
1630+
if (aliasFilterCanMatch == false) {
1631+
return new CanMatchResponse(false, null);
1632+
}
1633+
1634+
// null query means match_all
1635+
boolean canMatch = canRewriteToMatchNone(request.source()) == false
1636+
|| request.source().query() instanceof MatchNoneQueryBuilder == false;
1637+
if (canMatch == false) {
1638+
return new CanMatchResponse(false, null);
16341639
}
1635-
final FieldDoc searchAfterFieldDoc = getSearchAfterFieldDoc(request, context);
1636-
final Integer trackTotalHitsUpto = request.source() == null ? null : request.source().trackTotalHitsUpTo();
1637-
canMatch = canMatch && canMatchSearchAfter(searchAfterFieldDoc, minMax, sortBuilder, trackTotalHitsUpto);
16381640

1639-
return new CanMatchResponse(canMatch || hasRefreshPending, minMax);
1641+
final FieldSortBuilder sortBuilder = FieldSortBuilder.getPrimaryFieldSortOrNull(request.source());
1642+
final MinAndMax<?> minMax = sortBuilder != null ? FieldSortBuilder.getMinMaxOrNull(context, sortBuilder) : null;
1643+
final Object primarySearchAfterField = SearchAfterBuilder.getPrimarySearchAfterFieldOrNull(request.source());
1644+
if (minMax != null && primarySearchAfterField != null) {
1645+
final FieldDoc searchAfterFieldDoc = getPrimarySearchAfterFieldDoc(sortBuilder, primarySearchAfterField, context);
1646+
final Integer trackTotalHitsUpto = request.source() == null ? null : request.source().trackTotalHitsUpTo();
1647+
canMatch = canMatchSearchAfter(searchAfterFieldDoc, minMax, sortBuilder, trackTotalHitsUpto);
1648+
}
1649+
return new CanMatchResponse(canMatch, minMax);
16401650
}
16411651
}
16421652
}
@@ -1672,16 +1682,14 @@ public static boolean canMatchSearchAfter(
16721682
return true;
16731683
}
16741684

1675-
private static FieldDoc getSearchAfterFieldDoc(ShardSearchRequest request, QueryShardContext context) throws IOException {
1676-
if (context != null && request != null && request.source() != null && request.source().sorts() != null) {
1677-
final List<SortBuilder<?>> sorts = request.source().sorts();
1678-
final Object[] searchAfter = request.source().searchAfter();
1679-
final Optional<SortAndFormats> sortOpt = SortBuilder.buildSort(sorts, context);
1680-
if (sortOpt.isPresent() && !CollectionUtils.isEmpty(searchAfter)) {
1681-
return SearchAfterBuilder.buildFieldDoc(sortOpt.get(), searchAfter);
1682-
}
1683-
}
1684-
return null;
1685+
private static FieldDoc getPrimarySearchAfterFieldDoc(
1686+
FieldSortBuilder primarySortBuilder,
1687+
Object primarySearchAfter,
1688+
QueryShardContext context
1689+
) throws IOException {
1690+
final Optional<SortAndFormats> sortOpt = SortBuilder.buildSort(List.of(primarySortBuilder), context);
1691+
return sortOpt.map(sortAndFormats -> SearchAfterBuilder.buildFieldDoc(sortAndFormats, new Object[] { primarySearchAfter }))
1692+
.orElse(null);
16851693
}
16861694

16871695
/**

server/src/main/java/org/opensearch/search/searchafter/SearchAfterBuilder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@
4444
import org.opensearch.core.common.io.stream.StreamOutput;
4545
import org.opensearch.core.common.io.stream.Writeable;
4646
import org.opensearch.core.common.text.Text;
47+
import org.opensearch.core.common.util.CollectionUtils;
4748
import org.opensearch.core.xcontent.ToXContentObject;
4849
import org.opensearch.core.xcontent.XContentBuilder;
4950
import org.opensearch.core.xcontent.XContentParser;
5051
import org.opensearch.index.fielddata.IndexFieldData;
5152
import org.opensearch.search.DocValueFormat;
53+
import org.opensearch.search.builder.SearchSourceBuilder;
5254
import org.opensearch.search.sort.SortAndFormats;
5355

5456
import java.io.IOException;
@@ -148,6 +150,13 @@ public static FieldDoc buildFieldDoc(SortAndFormats sort, Object[] values) {
148150
return new FieldDoc(Integer.MAX_VALUE, 0, fieldValues);
149151
}
150152

153+
public static Object getPrimarySearchAfterFieldOrNull(SearchSourceBuilder source) {
154+
if (source == null || CollectionUtils.isEmpty(source.searchAfter())) {
155+
return null;
156+
}
157+
return source.searchAfter()[0];
158+
}
159+
151160
/**
152161
* Returns the inner {@link SortField.Type} expected for this sort field.
153162
*/

server/src/main/java/org/opensearch/search/sort/FieldSortBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.opensearch.core.common.ParsingException;
4848
import org.opensearch.core.common.io.stream.StreamInput;
4949
import org.opensearch.core.common.io.stream.StreamOutput;
50+
import org.opensearch.core.common.util.CollectionUtils;
5051
import org.opensearch.core.xcontent.ObjectParser;
5152
import org.opensearch.core.xcontent.ObjectParser.ValueType;
5253
import org.opensearch.core.xcontent.XContent;
@@ -599,7 +600,7 @@ public static boolean hasPrimaryFieldSort(SearchSourceBuilder source) {
599600
* is an instance of this class, null otherwise.
600601
*/
601602
public static FieldSortBuilder getPrimaryFieldSortOrNull(SearchSourceBuilder source) {
602-
if (source == null || source.sorts() == null || source.sorts().isEmpty()) {
603+
if (source == null || CollectionUtils.isEmpty(source.sorts())) {
603604
return null;
604605
}
605606
return source.sorts().get(0) instanceof FieldSortBuilder ? (FieldSortBuilder) source.sorts().get(0) : null;

0 commit comments

Comments
 (0)