LUCENE-7677: Cache compound filters earlier than regular filters.

This commit is contained in:
Adrien Grand 2017-02-16 09:42:50 +01:00
parent 063954ce79
commit 2d3487dba2
3 changed files with 96 additions and 1 deletions

View File

@ -149,6 +149,10 @@ Improvements
since they are plenty fast. This also has the side-effect of leaving more
space in the history for costly filters. (Adrien Grand)
* LUCENE-7677: UsageTrackingQueryCachingPolicy now caches compound queries a bit
earlier than regular queries in order to improve cache efficiency.
(Adrien Grand)
Optimizations
* LUCENE-7641: Optimized point range queries to compute documents that do not

View File

@ -122,7 +122,17 @@ public class UsageTrackingQueryCachingPolicy implements QueryCachingPolicy {
return 2;
} else {
// default: cache after the filter has been seen 5 times
return 5;
int minFrequency = 5;
if (query instanceof BooleanQuery
|| query instanceof DisjunctionMaxQuery) {
// Say you keep reusing a boolean query that looks like "A OR B" and
// never use the A and B queries out of that context. 5 times after it
// has been used, we would cache both A, B and A OR B, which is
// wasteful. So instead we cache compound queries a bit earlier so that
// we would only cache "A OR B" in that case.
minFrequency--;
}
return minFrequency;
}
}

View File

@ -18,8 +18,14 @@ package org.apache.lucene.search;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.LuceneTestCase;
public class TestUsageTrackingFilterCachingPolicy extends LuceneTestCase {
@ -48,4 +54,79 @@ public class TestUsageTrackingFilterCachingPolicy extends LuceneTestCase {
assertFalse(policy.shouldCache(q));
}
public void testBooleanQueries() throws IOException {
Directory dir = newDirectory();
RandomIndexWriter w = new RandomIndexWriter(random(), dir);
w.addDocument(new Document());
IndexReader reader = w.getReader();
w.close();
IndexSearcher searcher = new IndexSearcher(reader);
UsageTrackingQueryCachingPolicy policy = new UsageTrackingQueryCachingPolicy();
LRUQueryCache cache = new LRUQueryCache(10, Long.MAX_VALUE, new LRUQueryCache.MinSegmentSizePredicate(1, 0f));
searcher.setQueryCache(cache);
searcher.setQueryCachingPolicy(policy);
DummyQuery q1 = new DummyQuery(1);
DummyQuery q2 = new DummyQuery(2);
BooleanQuery bq = new BooleanQuery.Builder()
.add(q1, Occur.SHOULD)
.add(q2, Occur.SHOULD)
.build();
for (int i = 0; i < 3; ++i) {
searcher.count(bq);
}
assertEquals(0, cache.getCacheSize()); // nothing cached yet, too early
searcher.count(bq);
assertEquals(1, cache.getCacheSize()); // the bq got cached, but not q1 and q2
for (int i = 0; i < 10; ++i) {
searcher.count(bq);
}
assertEquals(1, cache.getCacheSize()); // q1 and q2 still not cached since we do not pull scorers on them
searcher.count(q1);
assertEquals(2, cache.getCacheSize()); // q1 used on its own -> cached
reader.close();
dir.close();
}
private static class DummyQuery extends Query {
private final int id;
DummyQuery(int id) {
this.id = id;
}
@Override
public String toString(String field) {
return "dummy";
}
@Override
public boolean equals(Object obj) {
return sameClassAs(obj) && ((DummyQuery) obj).id == id;
}
@Override
public int hashCode() {
return id;
}
@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
return new ConstantScoreWeight(DummyQuery.this, boost) {
@Override
public Scorer scorer(LeafReaderContext context) throws IOException {
return new ConstantScoreScorer(this, score(), DocIdSetIterator.all(1));
}
};
}
}
}