You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by be...@apache.org on 2025/07/16 15:54:08 UTC
(lucene) branch branch_10x updated: Knn dont filter match all (#14936)
This is an automated email from the ASF dual-hosted git repository.
benwtrent pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/lucene.git
The following commit(s) were added to refs/heads/branch_10x by this push:
new e32b39fa0a2 Knn dont filter match all (#14936)
e32b39fa0a2 is described below
commit e32b39fa0a2317cd03645cd90a4470ac25949318
Author: Benjamin Trent <be...@gmail.com>
AuthorDate: Wed Jul 16 11:33:39 2025 -0400
Knn dont filter match all (#14936)
If a given filter is a MatchAllQuery, we shouldn't bother going through the filtered search path. It adds unnecessary overhead through:
building a bitset for filter checking
checking a bit set to see if a vector matches a filter
---
lucene/CHANGES.txt | 2 ++
.../lucene/search/AbstractKnnVectorQuery.java | 30 +++++++++++++++-------
.../lucene/search/BaseKnnVectorQueryTestCase.java | 14 ++++++++++
3 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index d60be30f5bb..d4cc1cc535b 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -116,6 +116,8 @@ Optimizations
* GITHUB#14935: Speed up PostingsEnum#nextPostings when block is encoded as bitset. (Guo Feng)
+* GITHUB#14936: Don't do the filtered knn path when the provided filter is a MatchAllDocsQuery. (Ben Trent)
+
Changes in Runtime Behavior
---------------------
* GITHUB#14823: Decrease TieredMergePolicy's default number of segments per
diff --git a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
index e68f5d64671..57e2859e5da 100644
--- a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java
@@ -72,16 +72,28 @@ abstract class AbstractKnnVectorQuery extends Query {
final Weight filterWeight;
if (filter != null) {
- BooleanQuery booleanQuery =
- new BooleanQuery.Builder()
- .add(filter, BooleanClause.Occur.FILTER)
- .add(new FieldExistsQuery(field), BooleanClause.Occur.FILTER)
- .build();
- Query rewritten = indexSearcher.rewrite(booleanQuery);
- if (rewritten.getClass() == MatchNoDocsQuery.class) {
- return rewritten;
+ // rewrite inner filter query first to determine if its a match all
+ // or match no docs query, so we can skip the knn search
+ Query rewrittenFilter = filter.rewrite(indexSearcher);
+ if (rewrittenFilter.getClass() == MatchNoDocsQuery.class) {
+ // If the filter is a match no docs query, we can also skip it
+ return rewrittenFilter;
+ }
+ if (rewrittenFilter.getClass() != MatchAllDocsQuery.class) {
+ BooleanQuery booleanQuery =
+ new BooleanQuery.Builder()
+ .add(filter, BooleanClause.Occur.FILTER)
+ .add(new FieldExistsQuery(field), BooleanClause.Occur.FILTER)
+ .build();
+ Query rewritten = indexSearcher.rewrite(booleanQuery);
+ if (rewritten.getClass() == MatchNoDocsQuery.class) {
+ return rewritten;
+ }
+ filterWeight = rewritten.createWeight(indexSearcher, ScoreMode.COMPLETE_NO_SCORES, 1f);
+ } else {
+ // If the filter is a match all docs query, we can skip it
+ filterWeight = null;
}
- filterWeight = indexSearcher.createWeight(rewritten, ScoreMode.COMPLETE_NO_SCORES, 1f);
} else {
filterWeight = null;
}
diff --git a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
index b26cddddff1..d5151069bef 100644
--- a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
+++ b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java
@@ -246,6 +246,20 @@ abstract class BaseKnnVectorQueryTestCase extends LuceneTestCase {
}
}
+ public void testMatchAllFilter() throws IOException {
+ try (Directory indexStore =
+ getIndexStore("field", new float[] {0, 1}, new float[] {1, 2}, new float[] {0, 0});
+ IndexReader reader = DirectoryReader.open(indexStore)) {
+ IndexSearcher searcher = newSearcher(reader);
+
+ // make sure we don't drop to exact search, even though the filter matches fewer than k docs
+ Query kvq =
+ getThrowingKnnVectorQuery("field", new float[] {0, 0}, 10, new MatchAllDocsQuery());
+ TopDocs topDocs = searcher.search(kvq, 3);
+ assertEquals(3, topDocs.totalHits.value());
+ }
+ }
+
/** testDimensionMismatch */
public void testDimensionMismatch() throws IOException {
try (Directory indexStore =