SOLR-13808: caching {!bool filter=..} by default.

This commit is contained in:
Mikhail Khludnev 2019-10-27 19:45:23 +01:00
parent e06ad4cfb5
commit 3f29fe0b80
4 changed files with 90 additions and 14 deletions

View File

@ -150,6 +150,8 @@ Upgrade Notes
If you prefer to keep the old (but insecure) serialization strategy, you can start your nodes using the If you prefer to keep the old (but insecure) serialization strategy, you can start your nodes using the
property: `-Dsolr.useUnsafeOverseerResponse=true`. Keep in mind that this will be removed in future version of Solr. property: `-Dsolr.useUnsafeOverseerResponse=true`. Keep in mind that this will be removed in future version of Solr.
* SOLR-13808: add cache=false into uderneath BoolQParser's filter clause or {"bool":{"filter":..}} to avoid caching in
filterCache. (Mikhail Khludnev)
New Features New Features
--------------------- ---------------------
@ -178,6 +180,8 @@ Improvements
* SOLR-13984: Java's SecurityManager sandbox can be enabled via environment variable, * SOLR-13984: Java's SecurityManager sandbox can be enabled via environment variable,
SOLR_SECURITY_MANAGER_ENABLED=true. (rmuir) SOLR_SECURITY_MANAGER_ENABLED=true. (rmuir)
* SOLR-13808: filter in BoolQParser and {"bool":{"filter":..}} in Query DSL are cached by default (Mikhail Khludnev)
Optimizations Optimizations
--------------------- ---------------------
(No changes) (No changes)

View File

@ -21,6 +21,7 @@ import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.SolrParams;
import org.apache.solr.query.FilterQuery;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
/** /**
@ -49,7 +50,18 @@ public class BoolQParserPlugin extends QParserPlugin {
private void addQueries(BooleanQuery.Builder builder, String[] subQueries, BooleanClause.Occur occur) throws SyntaxError { private void addQueries(BooleanQuery.Builder builder, String[] subQueries, BooleanClause.Occur occur) throws SyntaxError {
if (subQueries != null) { if (subQueries != null) {
for (String subQuery : subQueries) { for (String subQuery : subQueries) {
builder.add(subQuery(subQuery, null).parse(), occur); final QParser subParser = subQuery(subQuery, null);
Query extQuery;
if (BooleanClause.Occur.FILTER.equals(occur)) {
extQuery = subParser.getQuery();
if (!(extQuery instanceof ExtendedQuery) || (
((ExtendedQuery) extQuery).getCache())) {
extQuery = new FilterQuery(extQuery);
}
} else {
extQuery = subParser.parse();
}
builder.add(extQuery, occur);
} }
} }
} }

View File

@ -16,21 +16,30 @@
*/ */
package org.apache.solr.search.json; package org.apache.solr.search.json;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.JSONTestUtil; import org.apache.solr.JSONTestUtil;
import org.apache.solr.SolrTestCaseHS; import org.apache.solr.SolrTestCaseHS;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.CommonParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.CaffeineCache;
import org.apache.solr.search.DocSet;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
@LuceneTestCase.SuppressCodecs({"Lucene3x","Lucene40","Lucene41","Lucene42","Lucene45","Appending"}) @LuceneTestCase.SuppressCodecs({"Lucene3x","Lucene40","Lucene41","Lucene42","Lucene45","Appending"})
public class TestJsonRequest extends SolrTestCaseHS { public class TestJsonRequest extends SolrTestCaseHS {
private static SolrInstances servers; // for distributed testing private static SolrInstances servers; // for distributed testing
@SuppressWarnings("deprecation")
@BeforeClass @BeforeClass
public static void beforeTests() throws Exception { public static void beforeTests() throws Exception {
systemSetPropertySolrDisableShardsWhitelist("true"); systemSetPropertySolrDisableShardsWhitelist("true");
@ -44,6 +53,7 @@ public class TestJsonRequest extends SolrTestCaseHS {
} }
} }
@SuppressWarnings("deprecation")
@AfterClass @AfterClass
public static void afterTests() throws Exception { public static void afterTests() throws Exception {
JSONTestUtil.failRepeatedKeys = false; JSONTestUtil.failRepeatedKeys = false;
@ -54,7 +64,7 @@ public class TestJsonRequest extends SolrTestCaseHS {
systemClearPropertySolrDisableShardsWhitelist(); systemClearPropertySolrDisableShardsWhitelist();
} }
@Test @Test @Repeat(iterations = 100)
public void testLocalJsonRequest() throws Exception { public void testLocalJsonRequest() throws Exception {
doJsonRequest(Client.localClient, false); doJsonRequest(Client.localClient, false);
} }
@ -303,17 +313,9 @@ public class TestJsonRequest extends SolrTestCaseHS {
, "response/numFound==1" , "response/numFound==1"
); );
client.testJQ( params("json","{ " + assertCatANot1(client, "must");
" query : {" +
" bool : {" + testFilterCachingLocally(client);
" must : '{!lucene q.op=AND df=cat_s}A'" +
" must_not : '{!lucene v=\\'id:1\\'}'" +
" }" +
" }" +
"}")
, "response/numFound==1"
);
client.testJQ( params("json","{" + client.testJQ( params("json","{" +
" query : '*:*'," + " query : '*:*'," +
@ -407,6 +409,64 @@ public class TestJsonRequest extends SolrTestCaseHS {
} }
private static void testFilterCachingLocally(Client client) throws Exception {
if(client.getClientProvider()==null) {
final SolrQueryRequest request = req();
try {
final CaffeineCache<Query,DocSet> filterCache = (CaffeineCache<Query,DocSet>) request.getSearcher().getFilterCache();
filterCache.clear();
final TermQuery catA = new TermQuery(new Term("cat_s", "A"));
assertNull("cache is empty",filterCache.get(catA));
if(random().nextBoolean()) {
if(random().nextBoolean()) {
if(random().nextBoolean()) {
assertCatANot1(client, "must");
}else {
assertCatANot1(client, "must", "cat_s:A");
}
} else {
assertCatANot1(client, "must","{!lucene q.op=AND df=cat_s "+"cache="+random().nextBoolean()+"}A" );
}
} else {
assertCatANot1(client, "filter", "{!lucene q.op=AND df=cat_s cache=false}A");
}
assertNull("no cache still",filterCache.get(catA));
if (random().nextBoolean()) {
if (random().nextBoolean()) {
assertCatANot1(client, "filter", "cat_s:A");
} else {
assertCatANot1(client, "filter");
}
} else {
assertCatANot1(client, "filter","{!lucene q.op=AND df=cat_s cache=true}A");
}
assertNotNull("got cached ",filterCache.get(catA));
} finally {
request.close();
}
}
}
private static void assertCatANot1(Client client, final String occur) throws Exception {
assertCatANot1(client, occur, "{!lucene q.op=AND df=cat_s}A");
}
private static void assertCatANot1(Client client, final String occur, String catAclause) throws Exception {
client.testJQ( params("json","{ " +
" query : {" +
" bool : {" +
" " + occur + " : '"+ catAclause+ "'" +
" must_not : '{!lucene v=\\'id:1\\'}'" +
" }" +
" }" +
"}")
, "response/numFound==1"
);
}
public static void doJsonRequestWithTag(Client client) throws Exception { public static void doJsonRequestWithTag(Client client) throws Exception {
addDocs(client); addDocs(client);

View File

@ -188,7 +188,7 @@ A list of queries that *must not* appear in matching documents.
A list of queries *should* appear in matching documents. For a BooleanQuery with no `must` queries, one or more `should` queries must match a document for the BooleanQuery to match. A list of queries *should* appear in matching documents. For a BooleanQuery with no `must` queries, one or more `should` queries must match a document for the BooleanQuery to match.
`filter`:: `filter`::
A list of queries that *must* appear in matching documents. However, unlike `must`, the score of filter queries is ignored. A list of queries that *must* appear in matching documents. However, unlike `must`, the score of filter queries is ignored. Also, these queries are cached in filter cache. To avoid caching add either `cache=false` as local parameter, or `"cache":"false"` property to underneath Query DLS Object.
*Examples* *Examples*