You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2025/03/30 08:49:20 UTC
(lucene) branch branch_10x updated: Allow skip cache factor to be updated dynamically (#14412)
This is an automated email from the ASF dual-hosted git repository.
jpountz 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 f277b5e9198 Allow skip cache factor to be updated dynamically (#14412)
f277b5e9198 is described below
commit f277b5e919861366bc6ac0e44cbc3e6b6c8876fb
Author: Sagar <99...@users.noreply.github.com>
AuthorDate: Sun Mar 30 01:32:13 2025 -0700
Allow skip cache factor to be updated dynamically (#14412)
---
lucene/CHANGES.txt | 2 +
.../org/apache/lucene/search/LRUQueryCache.java | 24 +++++++--
.../apache/lucene/search/TestLRUQueryCache.java | 63 ++++++++++++++++++++++
3 files changed, 86 insertions(+), 3 deletions(-)
diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 2f48be27de2..daac7329b9e 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -63,6 +63,8 @@ New Features
* GITHUB#13470: Added `TopDocs#rrf` to combine multiple TopDocs instances using
reciprocal rank fusion. (Haren Lin, Adrien Grand)
+* GITHUB#14412: Allow skip cache factor to be updated dynamically. (Sagar Upadhyaya)
+
Improvements
---------------------
diff --git a/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java b/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java
index 0976f60220d..088a47bf0a9 100644
--- a/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java
+++ b/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java
@@ -99,7 +99,7 @@ public class LRUQueryCache implements QueryCache, Accountable {
private final Map<IndexReader.CacheKey, LeafCache> cache;
private final ReentrantReadWriteLock.ReadLock readLock;
private final ReentrantReadWriteLock.WriteLock writeLock;
- private final float skipCacheFactor;
+ private volatile float skipCacheFactor;
private final LongAdder hitCount;
private final LongAdder missCount;
@@ -142,6 +142,25 @@ public class LRUQueryCache implements QueryCache, Accountable {
missCount = new LongAdder();
}
+ /**
+ * Get the skip cache factor
+ *
+ * @return #setSkipCacheFactor
+ */
+ public float getSkipCacheFactor() {
+ return skipCacheFactor;
+ }
+
+ /**
+ * This setter enables the skipCacheFactor to be updated dynamically.
+ *
+ * @param skipCacheFactor clauses whose cost is {@code skipCacheFactor} times more than the cost
+ * of the top-level query will not be cached in order to not slow down queries too much.
+ */
+ public void setSkipCacheFactor(float skipCacheFactor) {
+ this.skipCacheFactor = skipCacheFactor;
+ }
+
/**
* Create a new instance that will cache at most <code>maxSize</code> queries with at most <code>
* maxRamBytesUsed</code> bytes of memory. Queries will only be cached on leaves that have more
@@ -706,13 +725,12 @@ public class LRUQueryCache implements QueryCache, Accountable {
private boolean cacheEntryHasReasonableWorstCaseSize(int maxDoc) {
// The worst-case (dense) is a bit set which needs one bit per document
final long worstCaseRamUsage = maxDoc / 8;
- final long totalRamAvailable = maxRamBytesUsed;
// Imagine the worst-case that a cache entry is large than the size of
// the cache: not only will this entry be trashed immediately but it
// will also evict all current entries from the cache. For this reason
// we only cache on an IndexReader if we have available room for
// 5 different filters on this reader to avoid excessive trashing
- return worstCaseRamUsage * 5 < totalRamAvailable;
+ return worstCaseRamUsage * 5 < maxRamBytesUsed;
}
/** Check whether this segment is eligible for caching, regardless of the query. */
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java
index 6f8b4fdb8fb..b81f05d3f92 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java
@@ -2134,4 +2134,67 @@ public class TestLRUQueryCache extends LuceneTestCase {
w.close();
dir.close();
}
+
+ public void testSkipCacheFactorWithDynamicValues() throws IOException {
+ Directory dir = newDirectory();
+ final RandomIndexWriter w = new RandomIndexWriter(random(), dir);
+ Document doc1 = new Document();
+ doc1.add(new StringField("name", "tom", Store.YES));
+ doc1.add(new StringField("hobby", "movie", Store.YES));
+ Document doc2 = new Document();
+ doc2.add(new StringField("name", "alice", Store.YES));
+ doc2.add(new StringField("hobby", "book", Store.YES));
+ Document doc3 = new Document();
+ doc3.add(new StringField("name", "alice", Store.YES));
+ doc3.add(new StringField("hobby", "movie", Store.YES));
+ w.addDocuments(Arrays.asList(doc1, doc2, doc3));
+ final IndexReader reader = w.getReader();
+ final IndexSearcher searcher = newSearcher(reader);
+ final QueryCachingPolicy policy =
+ new QueryCachingPolicy() {
+
+ @Override
+ public boolean shouldCache(Query query) throws IOException {
+ return query.getClass() != TermQuery.class;
+ }
+
+ @Override
+ public void onUse(Query query) {
+ // no-op
+ }
+ };
+ searcher.setQueryCachingPolicy(policy);
+ w.close();
+
+ // lead cost is 2, cost of subQuery1 is 3, cost of subQuery2 is 2
+ BooleanQuery.Builder inner = new BooleanQuery.Builder();
+ TermQuery innerSubQuery1 = new TermQuery(new Term("hobby", "book"));
+ TermQuery innerSubQuery2 = new TermQuery(new Term("hobby", "movie"));
+ BooleanQuery subQuery1 =
+ inner.add(innerSubQuery1, Occur.SHOULD).add(innerSubQuery2, Occur.SHOULD).build();
+
+ BooleanQuery.Builder bq = new BooleanQuery.Builder();
+ TermQuery subQuery2 = new TermQuery(new Term("name", "alice"));
+ BooleanQuery query =
+ bq.add(new ConstantScoreQuery(subQuery1), Occur.FILTER)
+ .add(subQuery2, Occur.FILTER)
+ .build();
+ Set<Query> cacheSet = new HashSet<>();
+
+ // Define skip cache factor to be 1, so that query is not cached.
+ final LRUQueryCache cache = new LRUQueryCache(1000000, 10000000, ctx -> true, 1.0f);
+ searcher.setQueryCache(cache);
+ searcher.search(query, 1);
+ assertEquals(cacheSet, new HashSet<>(cache.cachedQueries()));
+ assertEquals(1.0, cache.getSkipCacheFactor(), 0);
+
+ // Now change the skipCacheFactor to 3.0f, now same query should get cached.
+ cache.setSkipCacheFactor(3.0f);
+ searcher.search(query, 1);
+ assertEquals(new HashSet<>(List.of(subQuery1)), new HashSet<>(cache.cachedQueries()));
+ assertEquals(3.0, cache.getSkipCacheFactor(), 0);
+
+ reader.close();
+ dir.close();
+ }
}