SOLR-8496: multi-select faceting and getDocSet(List<Query>) can match deleted docs

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1725005 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2016-01-16 16:56:38 +00:00
parent 4633d125d1
commit d231546a5f
3 changed files with 45 additions and 5 deletions

View File

@ -556,6 +556,12 @@ Bug Fixes
* SOLR-7462: AIOOBE in RecordingJSONParser (Scott Dawson, noble)
* SOLR-8496: SolrIndexSearcher.getDocSet(List<Query>) incorrectly included deleted documents
when all of the queries were uncached (or there was no filter cache). This caused
multi-select faceting (including the JSON Facet API) to include deleted doc counts
when the remaining non-excluded filters were all uncached. This bug was first introduced in 5.3.0
(Andreas Müller, Vasiliy Bout, Erick Erickson, Shawn Heisey, Hossman, yonik)
New Features
----------------------
@ -1040,6 +1046,13 @@ Bug Fixes
* SOLR-8422: When authentication enabled, requests fail if sent to a node that doesn't host
the collection (noble)
* SOLR-8496: SolrIndexSearcher.getDocSet(List<Query>) incorrectly included deleted documents
when all of the queries were uncached (or there was no filter cache). This caused
multi-select faceting (including the JSON Facet API) to include deleted doc counts
when the remaining non-excluded filters were all uncached. This bug was first introduced in 5.3.0
(Andreas Müller, Vasiliy Bout, Erick Erickson, Shawn Heisey, Hossman, yonik)
================== 5.3.1 ==================
Bug Fixes

View File

@ -1044,6 +1044,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
public DocSet answer; // the answer, if non-null
public Filter filter;
public DelegatingCollector postFilter;
public boolean hasDeletedDocs; // true if it's possible that filter may match deleted docs
}
private static Comparator<Query> sortByCost = new Comparator<Query>() {
@ -1107,7 +1108,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
for (final LeafReaderContext leaf : leafContexts) {
final LeafReader reader = leaf.reader();
final Bits liveDocs = reader.getLiveDocs(); // TODO: the filter may already only have liveDocs...
Bits liveDocs = reader.getLiveDocs();
DocIdSet idSet = null;
if (pf.filter != null) {
idSet = pf.filter.getDocIdSet(leaf, liveDocs);
@ -1117,6 +1118,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
if (idSet != null) {
idIter = idSet.iterator();
if (idIter == null) continue;
if (!pf.hasDeletedDocs) liveDocs = null; // no need to check liveDocs
}
final LeafCollector leafCollector = collector.getLeafCollector(leaf);
@ -1128,10 +1130,18 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
leafCollector.collect(docid);
}
} else {
for (int docid = -1; (docid = idIter.advance(docid + 1)) < max;) {
leafCollector.collect(docid);
if (liveDocs != null) {
for (int docid = -1; (docid = idIter.advance(docid + 1)) < max; ) {
if (liveDocs.get(docid))
leafCollector.collect(docid);
}
} else {
for (int docid = -1; (docid = idIter.advance(docid + 1)) < max;) {
leafCollector.collect(docid);
}
}
}
}
if (collector instanceof DelegatingCollector) {
@ -1231,6 +1241,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
weights.add(createNormalizedWeight(qq, true));
}
pf.filter = new FilterImpl(answer, weights);
pf.hasDeletedDocs = (answer == null); // if all clauses were uncached, the resulting filter may match deleted docs
} else {
if (postFilters == null) {
if (answer == null) {

View File

@ -382,7 +382,11 @@ public class TestJsonFacets extends SolrTestCaseHS {
client.deleteByQuery("*:*", null);
client.add(sdoc("id", "1", cat_s, "A", where_s, "NY", num_d, "4", num_i, "2", super_s, "zodiac", date,"2001-01-01T01:01:01Z", val_b, "true", sparse_s, "one"), null);
SolrInputDocument doc =
sdoc("id", "1", cat_s, "A", where_s, "NY", num_d, "4", num_i, "2", super_s, "zodiac", date, "2001-01-01T01:01:01Z", val_b, "true", sparse_s, "one");
client.add(doc, null);
client.add(doc, null);
client.add(doc, null); // a couple of deleted docs
client.add(sdoc("id", "2", cat_s, "B", where_s, "NJ", num_d, "-9", num_i, "-5", super_s,"superman", date,"2002-02-02T02:02:02Z", val_b, "false" , multi_ss,"a", multi_ss,"b" , Z_num_i, "0"), null);
client.add(sdoc("id", "3"), null);
client.commit();
@ -927,6 +931,18 @@ public class TestJsonFacets extends SolrTestCaseHS {
// multi-select / exclude tagged filters via excludeTags
////////////////////////////////////////////////////////////////////////////////////////////
// test uncached multi-select (see SOLR-8496)
client.testJQ(params(p, "q", "{!cache=false}*:*", "fq","{!tag=doc3,allfilt}-id:3"
, "json.facet", "{" +
"f1:{${terms} type:terms, field:${cat_s}, domain:{excludeTags:doc3} } " +
"}"
)
, "facets=={ count:5, " +
" f1:{ buckets:[ {val:B, count:3}, {val:A, count:2} ] }" +
"}"
);
// nested query facets on subset (with excludeTags)
client.testJQ(params(p, "q", "*:*", "fq","{!tag=abc}id:(2 3)"
, "json.facet", "{ processEmpty:true," +
@ -951,7 +967,7 @@ public class TestJsonFacets extends SolrTestCaseHS {
);
// terms facet with nested query facet (with excludeTags, using new format inside domain:{})
client.testJQ(params(p, "q", "*:*", "fq", "{!tag=doc6,allfilt}-id:6", "fq","{!tag=doc3,allfilt}-id:3"
client.testJQ(params(p, "q", "{!cache=false}*:*", "fq", "{!tag=doc6,allfilt}-id:6", "fq","{!tag=doc3,allfilt}-id:3"
, "json.facet", "{processEmpty:true, " +
" f0:{${terms} type:terms, field:${cat_s}, facet:{nj:{query:'${where_s}:NJ'}} } " +