mirror of https://github.com/apache/lucene.git
LUCENE-4964: allow custom per-dimension drill-down queries
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1477315 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b8fd868366
commit
9fc0678da1
|
@ -95,6 +95,10 @@ New Features
|
|||
* SOLR-4761: Add SimpleMergedSegmentWarmer, which just initializes terms,
|
||||
norms, docvalues, and so on. (Mark Miller, Mike McCandless, Robert Muir)
|
||||
|
||||
* LUCENE-4964: Allow arbitrary Query for per-dimension drill-down to
|
||||
DrillDownQuery and DrillSideways, to support future dynamic faceting
|
||||
methods (Mike McCandless)
|
||||
|
||||
======================= Lucene 4.3.0 =======================
|
||||
|
||||
Changes in backwards compatibility policy
|
||||
|
|
|
@ -167,11 +167,25 @@ public final class DrillDownQuery extends Query {
|
|||
}
|
||||
q = bq;
|
||||
}
|
||||
drillDownDims.put(dim, drillDownDims.size());
|
||||
|
||||
final ConstantScoreQuery drillDownQuery = new ConstantScoreQuery(q);
|
||||
add(dim, q);
|
||||
}
|
||||
|
||||
/** Expert: add a custom drill-down subQuery. Use this
|
||||
* when you have a separate way to drill-down on the
|
||||
* dimension than the indexed facet ordinals. */
|
||||
public void add(String dim, Query subQuery) {
|
||||
|
||||
// TODO: we should use FilteredQuery?
|
||||
|
||||
// So scores of the drill-down query don't have an
|
||||
// effect:
|
||||
final ConstantScoreQuery drillDownQuery = new ConstantScoreQuery(subQuery);
|
||||
drillDownQuery.setBoost(0.0f);
|
||||
|
||||
query.add(drillDownQuery, Occur.MUST);
|
||||
|
||||
drillDownDims.put(dim, drillDownDims.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Set;
|
|||
|
||||
import org.apache.lucene.facet.params.FacetSearchParams;
|
||||
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
|
@ -43,6 +44,7 @@ import org.apache.lucene.search.TermQuery;
|
|||
import org.apache.lucene.search.TopDocs;
|
||||
import org.apache.lucene.search.TopFieldCollector;
|
||||
import org.apache.lucene.search.TopScoreDocCollector;
|
||||
import org.apache.lucene.search.Weight;
|
||||
|
||||
/**
|
||||
* Computes drill down and sideways counts for the provided
|
||||
|
@ -149,7 +151,7 @@ public class DrillSideways {
|
|||
Map<String,Integer> drillDownDims = query.getDims();
|
||||
|
||||
if (drillDownDims.isEmpty()) {
|
||||
// Just do ordinary search:
|
||||
// Just do ordinary search when there are no drill-downs:
|
||||
FacetsCollector c = FacetsCollector.create(getDrillDownAccumulator(fsp));
|
||||
searcher.search(query, MultiCollector.wrap(hitCollector, c));
|
||||
return new DrillSidewaysResult(c.getFacetResults(), null);
|
||||
|
@ -171,25 +173,6 @@ public class DrillSideways {
|
|||
startClause = 1;
|
||||
}
|
||||
|
||||
Term[][] drillDownTerms = new Term[clauses.length-startClause][];
|
||||
for(int i=startClause;i<clauses.length;i++) {
|
||||
Query q = clauses[i].getQuery();
|
||||
assert q instanceof ConstantScoreQuery;
|
||||
q = ((ConstantScoreQuery) q).getQuery();
|
||||
assert q instanceof TermQuery || q instanceof BooleanQuery;
|
||||
if (q instanceof TermQuery) {
|
||||
drillDownTerms[i-startClause] = new Term[] {((TermQuery) q).getTerm()};
|
||||
} else {
|
||||
BooleanQuery q2 = (BooleanQuery) q;
|
||||
BooleanClause[] clauses2 = q2.getClauses();
|
||||
drillDownTerms[i-startClause] = new Term[clauses2.length];
|
||||
for(int j=0;j<clauses2.length;j++) {
|
||||
assert clauses2[j].getQuery() instanceof TermQuery;
|
||||
drillDownTerms[i-startClause][j] = ((TermQuery) clauses2[j].getQuery()).getTerm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FacetsCollector drillDownCollector = FacetsCollector.create(getDrillDownAccumulator(fsp));
|
||||
|
||||
FacetsCollector[] drillSidewaysCollectors = new FacetsCollector[drillDownDims.size()];
|
||||
|
@ -209,9 +192,53 @@ public class DrillSideways {
|
|||
drillSidewaysCollectors[idx++] = FacetsCollector.create(getDrillSidewaysAccumulator(dim, new FacetSearchParams(fsp.indexingParams, requests)));
|
||||
}
|
||||
|
||||
DrillSidewaysQuery dsq = new DrillSidewaysQuery(baseQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms, scoreSubDocsAtOnce());
|
||||
boolean useCollectorMethod = scoreSubDocsAtOnce();
|
||||
|
||||
searcher.search(dsq, hitCollector);
|
||||
Term[][] drillDownTerms = null;
|
||||
|
||||
if (!useCollectorMethod) {
|
||||
// Optimistic: assume subQueries of the DDQ are either
|
||||
// TermQuery or BQ OR of TermQuery; if this is wrong
|
||||
// then we detect it and fallback to the mome general
|
||||
// but slower DrillSidewaysCollector:
|
||||
drillDownTerms = new Term[clauses.length-startClause][];
|
||||
for(int i=startClause;i<clauses.length;i++) {
|
||||
Query q = clauses[i].getQuery();
|
||||
|
||||
// DrillDownQuery always wraps each subQuery in
|
||||
// ConstantScoreQuery:
|
||||
assert q instanceof ConstantScoreQuery;
|
||||
|
||||
q = ((ConstantScoreQuery) q).getQuery();
|
||||
|
||||
if (q instanceof TermQuery) {
|
||||
drillDownTerms[i-startClause] = new Term[] {((TermQuery) q).getTerm()};
|
||||
} else if (q instanceof BooleanQuery) {
|
||||
BooleanQuery q2 = (BooleanQuery) q;
|
||||
BooleanClause[] clauses2 = q2.getClauses();
|
||||
drillDownTerms[i-startClause] = new Term[clauses2.length];
|
||||
for(int j=0;j<clauses2.length;j++) {
|
||||
if (clauses2[j].getQuery() instanceof TermQuery) {
|
||||
drillDownTerms[i-startClause][j] = ((TermQuery) clauses2[j].getQuery()).getTerm();
|
||||
} else {
|
||||
useCollectorMethod = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useCollectorMethod) {
|
||||
// TODO: maybe we could push the "collector method"
|
||||
// down into the optimized scorer to have a tighter
|
||||
// integration ... and so TermQuery clauses could
|
||||
// continue to run "optimized"
|
||||
collectorMethod(query, baseQuery, startClause, hitCollector, drillDownCollector, drillSidewaysCollectors);
|
||||
} else {
|
||||
DrillSidewaysQuery dsq = new DrillSidewaysQuery(baseQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms);
|
||||
searcher.search(dsq, hitCollector);
|
||||
}
|
||||
|
||||
int numDims = drillDownDims.size();
|
||||
List<FacetResult>[] drillSidewaysResults = new List[numDims];
|
||||
|
@ -230,7 +257,9 @@ public class DrillSideways {
|
|||
// Lazy init, in case all requests were against
|
||||
// drill-sideways dims:
|
||||
drillDownResults = drillDownCollector.getFacetResults();
|
||||
//System.out.println("get DD results");
|
||||
}
|
||||
//System.out.println("add dd results " + i);
|
||||
mergedResults.add(drillDownResults.get(i));
|
||||
} else {
|
||||
// Drill sideways dim:
|
||||
|
@ -250,6 +279,93 @@ public class DrillSideways {
|
|||
return new DrillSidewaysResult(mergedResults, null);
|
||||
}
|
||||
|
||||
/** Uses the more general but slower method of sideways
|
||||
* counting. This method allows an arbitrary subQuery to
|
||||
* implement the drill down for a given dimension. */
|
||||
private void collectorMethod(DrillDownQuery ddq, Query baseQuery, int startClause, Collector hitCollector, Collector drillDownCollector, Collector[] drillSidewaysCollectors) throws IOException {
|
||||
|
||||
BooleanClause[] clauses = ddq.getBooleanQuery().getClauses();
|
||||
|
||||
Map<String,Integer> drillDownDims = ddq.getDims();
|
||||
|
||||
BooleanQuery topQuery = new BooleanQuery(true);
|
||||
final DrillSidewaysCollector collector = new DrillSidewaysCollector(hitCollector, drillDownCollector, drillSidewaysCollectors,
|
||||
drillDownDims);
|
||||
|
||||
// TODO: if query is already a BQ we could copy that and
|
||||
// add clauses to it, instead of doing BQ inside BQ
|
||||
// (should be more efficient)? Problem is this can
|
||||
// affect scoring (coord) ... too bad we can't disable
|
||||
// coord on a clause by clause basis:
|
||||
topQuery.add(baseQuery, BooleanClause.Occur.MUST);
|
||||
|
||||
// NOTE: in theory we could just make a single BQ, with
|
||||
// +query a b c minShouldMatch=2, but in this case,
|
||||
// annoyingly, BS2 wraps a sub-scorer that always
|
||||
// returns 2 as the .freq(), not how many of the
|
||||
// SHOULD clauses matched:
|
||||
BooleanQuery subQuery = new BooleanQuery(true);
|
||||
|
||||
Query wrappedSubQuery = new QueryWrapper(subQuery,
|
||||
new SetWeight() {
|
||||
@Override
|
||||
public void set(Weight w) {
|
||||
collector.setWeight(w, -1);
|
||||
}
|
||||
});
|
||||
Query constantScoreSubQuery = new ConstantScoreQuery(wrappedSubQuery);
|
||||
|
||||
// Don't impact score of original query:
|
||||
constantScoreSubQuery.setBoost(0.0f);
|
||||
|
||||
topQuery.add(constantScoreSubQuery, BooleanClause.Occur.MUST);
|
||||
|
||||
// Unfortunately this sub-BooleanQuery
|
||||
// will never get BS1 because today BS1 only works
|
||||
// if topScorer=true... and actually we cannot use BS1
|
||||
// anyways because we need subDocsScoredAtOnce:
|
||||
int dimIndex = 0;
|
||||
for(int i=startClause;i<clauses.length;i++) {
|
||||
Query q = clauses[i].getQuery();
|
||||
// DrillDownQuery always wraps each subQuery in
|
||||
// ConstantScoreQuery:
|
||||
assert q instanceof ConstantScoreQuery;
|
||||
q = ((ConstantScoreQuery) q).getQuery();
|
||||
|
||||
final int finalDimIndex = dimIndex;
|
||||
subQuery.add(new QueryWrapper(q,
|
||||
new SetWeight() {
|
||||
@Override
|
||||
public void set(Weight w) {
|
||||
collector.setWeight(w, finalDimIndex);
|
||||
}
|
||||
}),
|
||||
BooleanClause.Occur.SHOULD);
|
||||
dimIndex++;
|
||||
}
|
||||
|
||||
// TODO: we could better optimize the "just one drill
|
||||
// down" case w/ a separate [specialized]
|
||||
// collector...
|
||||
int minShouldMatch = drillDownDims.size()-1;
|
||||
if (minShouldMatch == 0) {
|
||||
// Must add another "fake" clause so BQ doesn't erase
|
||||
// itself by rewriting to the single clause:
|
||||
Query end = new MatchAllDocsQuery();
|
||||
end.setBoost(0.0f);
|
||||
subQuery.add(end, BooleanClause.Occur.SHOULD);
|
||||
minShouldMatch++;
|
||||
}
|
||||
|
||||
subQuery.setMinimumNumberShouldMatch(minShouldMatch);
|
||||
|
||||
//System.out.println("EXE " + topQuery);
|
||||
|
||||
// Collects against the passed-in
|
||||
// drillDown/SidewaysCollectors as a side effect:
|
||||
searcher.search(topQuery, collector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search, sorting by {@link Sort}, and computing
|
||||
* drill down and sideways counts.
|
||||
|
@ -327,5 +443,55 @@ public class DrillSideways {
|
|||
this.hits = hits;
|
||||
}
|
||||
}
|
||||
|
||||
private interface SetWeight {
|
||||
public void set(Weight w);
|
||||
}
|
||||
|
||||
/** Just records which Weight was given out for the
|
||||
* (possibly rewritten) Query. */
|
||||
private static class QueryWrapper extends Query {
|
||||
private final Query originalQuery;
|
||||
private final SetWeight setter;
|
||||
|
||||
public QueryWrapper(Query originalQuery, SetWeight setter) {
|
||||
this.originalQuery = originalQuery;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Weight createWeight(final IndexSearcher searcher) throws IOException {
|
||||
Weight w = originalQuery.createWeight(searcher);
|
||||
setter.set(w);
|
||||
return w;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query rewrite(IndexReader reader) throws IOException {
|
||||
Query rewritten = originalQuery.rewrite(reader);
|
||||
if (rewritten != originalQuery) {
|
||||
return new QueryWrapper(rewritten, setter);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(String s) {
|
||||
return originalQuery.toString(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof QueryWrapper)) return false;
|
||||
final QueryWrapper other = (QueryWrapper) o;
|
||||
return super.equals(o) && originalQuery.equals(other.originalQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode() * 31 + originalQuery.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
package org.apache.lucene.facet.search;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.Collector;
|
||||
import org.apache.lucene.search.Scorer.ChildScorer;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
import org.apache.lucene.search.Weight;
|
||||
|
||||
/** Collector that scrutinizes each hit to determine if it
|
||||
* passed all constraints (a true hit) or if it missed
|
||||
* exactly one dimension (a near-miss, to count for
|
||||
* drill-sideways counts on that dimension). */
|
||||
class DrillSidewaysCollector extends Collector {
|
||||
|
||||
private final Collector hitCollector;
|
||||
private final Collector drillDownCollector;
|
||||
private final Collector[] drillSidewaysCollectors;
|
||||
private final Scorer[] subScorers;
|
||||
private final int exactCount;
|
||||
|
||||
// Maps Weight to either -1 (mainQuery) or to integer
|
||||
// index of the dims drillDown. We needs this when
|
||||
// visiting the child scorers to correlate back to the
|
||||
// right scorers:
|
||||
private final Map<Weight,Integer> weightToIndex = new IdentityHashMap<Weight,Integer>();
|
||||
|
||||
private Scorer mainScorer;
|
||||
|
||||
public DrillSidewaysCollector(Collector hitCollector, Collector drillDownCollector, Collector[] drillSidewaysCollectors,
|
||||
Map<String,Integer> dims) {
|
||||
this.hitCollector = hitCollector;
|
||||
this.drillDownCollector = drillDownCollector;
|
||||
this.drillSidewaysCollectors = drillSidewaysCollectors;
|
||||
subScorers = new Scorer[dims.size()];
|
||||
|
||||
if (dims.size() == 1) {
|
||||
// When we have only one dim, we insert the
|
||||
// MatchAllDocsQuery, bringing the clause count to
|
||||
// 2:
|
||||
exactCount = 2;
|
||||
} else {
|
||||
exactCount = dims.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collect(int doc) throws IOException {
|
||||
//System.out.println("collect doc=" + doc + " main.freq=" + mainScorer.freq() + " main.doc=" + mainScorer.docID() + " exactCount=" + exactCount);
|
||||
|
||||
if (mainScorer == null) {
|
||||
// This segment did not have any docs with any
|
||||
// drill-down field & value:
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainScorer.freq() == exactCount) {
|
||||
// All sub-clauses from the drill-down filters
|
||||
// matched, so this is a "real" hit, so we first
|
||||
// collect in both the hitCollector and the
|
||||
// drillDown collector:
|
||||
//System.out.println(" hit " + drillDownCollector);
|
||||
hitCollector.collect(doc);
|
||||
drillDownCollector.collect(doc);
|
||||
|
||||
// Also collect across all drill-sideways counts so
|
||||
// we "merge in" drill-down counts for this
|
||||
// dimension.
|
||||
for(int i=0;i<subScorers.length;i++) {
|
||||
// This cannot be null, because it was a hit,
|
||||
// meaning all drill-down dims matched, so all
|
||||
// dims must have non-null scorers:
|
||||
assert subScorers[i] != null;
|
||||
int subDoc = subScorers[i].docID();
|
||||
assert subDoc == doc;
|
||||
drillSidewaysCollectors[i].collect(doc);
|
||||
}
|
||||
|
||||
} else {
|
||||
for(int i=0;i<subScorers.length;i++) {
|
||||
if (subScorers[i] == null) {
|
||||
// This segment did not have any docs with this
|
||||
// drill-down field & value:
|
||||
continue;
|
||||
}
|
||||
int subDoc = subScorers[i].docID();
|
||||
//System.out.println(" sub: " + subDoc);
|
||||
if (subDoc != doc) {
|
||||
assert subDoc > doc: "subDoc=" + subDoc + " doc=" + doc;
|
||||
drillSidewaysCollectors[i].collect(doc);
|
||||
assert allMatchesFrom(i+1, doc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only used by assert:
|
||||
private boolean allMatchesFrom(int startFrom, int doc) {
|
||||
for(int i=startFrom;i<subScorers.length;i++) {
|
||||
assert subScorers[i].docID() == doc;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptsDocsOutOfOrder() {
|
||||
// We actually could accept docs out of order, but, we
|
||||
// need to force BooleanScorer2 so that the
|
||||
// sub-scorers are "on" each docID we are collecting:
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextReader(AtomicReaderContext leaf) throws IOException {
|
||||
hitCollector.setNextReader(leaf);
|
||||
drillDownCollector.setNextReader(leaf);
|
||||
for(Collector dsc : drillSidewaysCollectors) {
|
||||
dsc.setNextReader(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
void setWeight(Weight weight, int index) {
|
||||
assert !weightToIndex.containsKey(weight);
|
||||
weightToIndex.put(weight, index);
|
||||
}
|
||||
|
||||
private void findScorers(Scorer scorer) {
|
||||
Integer index = weightToIndex.get(scorer.getWeight());
|
||||
if (index != null) {
|
||||
if (index.intValue() == -1) {
|
||||
mainScorer = scorer;
|
||||
} else {
|
||||
subScorers[index] = scorer;
|
||||
}
|
||||
}
|
||||
for(ChildScorer child : scorer.getChildren()) {
|
||||
findScorers(child.child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setScorer(Scorer scorer) throws IOException {
|
||||
mainScorer = null;
|
||||
Arrays.fill(subScorers, null);
|
||||
findScorers(scorer);
|
||||
hitCollector.setScorer(scorer);
|
||||
drillDownCollector.setScorer(scorer);
|
||||
for(Collector dsc : drillSidewaysCollectors) {
|
||||
dsc.setScorer(scorer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,14 +39,12 @@ class DrillSidewaysQuery extends Query {
|
|||
final Collector drillDownCollector;
|
||||
final Collector[] drillSidewaysCollectors;
|
||||
final Term[][] drillDownTerms;
|
||||
final boolean scoreSubDocsAtOnce;
|
||||
|
||||
DrillSidewaysQuery(Query baseQuery, Collector drillDownCollector, Collector[] drillSidewaysCollectors, Term[][] drillDownTerms, boolean scoreSubDocsAtOnce) {
|
||||
DrillSidewaysQuery(Query baseQuery, Collector drillDownCollector, Collector[] drillSidewaysCollectors, Term[][] drillDownTerms) {
|
||||
this.baseQuery = baseQuery;
|
||||
this.drillDownCollector = drillDownCollector;
|
||||
this.drillSidewaysCollectors = drillSidewaysCollectors;
|
||||
this.drillDownTerms = drillDownTerms;
|
||||
this.scoreSubDocsAtOnce = scoreSubDocsAtOnce;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,7 +65,7 @@ class DrillSidewaysQuery extends Query {
|
|||
if (newQuery == baseQuery) {
|
||||
return this;
|
||||
} else {
|
||||
return new DrillSidewaysQuery(newQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms, scoreSubDocsAtOnce);
|
||||
return new DrillSidewaysQuery(newQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +155,7 @@ class DrillSidewaysQuery extends Query {
|
|||
|
||||
return new DrillSidewaysScorer(this, context,
|
||||
baseScorer,
|
||||
drillDownCollector, dims, scoreSubDocsAtOnce);
|
||||
drillDownCollector, dims);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -43,19 +43,17 @@ class DrillSidewaysScorer extends Scorer {
|
|||
|
||||
private static final int CHUNK = 2048;
|
||||
private static final int MASK = CHUNK-1;
|
||||
private final boolean scoreSubDocsAtOnce;
|
||||
|
||||
private int collectDocID = -1;
|
||||
private float collectScore;
|
||||
|
||||
DrillSidewaysScorer(Weight w, AtomicReaderContext context, Scorer baseScorer, Collector drillDownCollector,
|
||||
DocsEnumsAndFreq[] dims, boolean scoreSubDocsAtOnce) {
|
||||
DocsEnumsAndFreq[] dims) {
|
||||
super(w);
|
||||
this.dims = dims;
|
||||
this.context = context;
|
||||
this.baseScorer = baseScorer;
|
||||
this.drillDownCollector = drillDownCollector;
|
||||
this.scoreSubDocsAtOnce = scoreSubDocsAtOnce;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,22 +112,15 @@ class DrillSidewaysScorer extends Scorer {
|
|||
}
|
||||
*/
|
||||
|
||||
//System.out.println("DS score " + scoreSubDocsAtOnce);
|
||||
if (!scoreSubDocsAtOnce) {
|
||||
if (baseQueryCost < drillDownCost/10) {
|
||||
//System.out.println("baseAdvance");
|
||||
doBaseAdvanceScoring(collector, docsEnums, sidewaysCollectors);
|
||||
} else if (numDims > 1 && (dims[1].maxCost < baseQueryCost/10)) {
|
||||
//System.out.println("drillDownAdvance");
|
||||
doDrillDownAdvanceScoring(collector, docsEnums, sidewaysCollectors);
|
||||
} else {
|
||||
//System.out.println("union");
|
||||
doUnionScoring(collector, docsEnums, sidewaysCollectors);
|
||||
}
|
||||
} else {
|
||||
// TODO: we should fallback to BS2 ReqOptSum scorer here
|
||||
if (baseQueryCost < drillDownCost/10) {
|
||||
//System.out.println("baseAdvance");
|
||||
doBaseAdvanceScoring(collector, docsEnums, sidewaysCollectors);
|
||||
} else if (numDims > 1 && (dims[1].maxCost < baseQueryCost/10)) {
|
||||
//System.out.println("drillDownAdvance");
|
||||
doDrillDownAdvanceScoring(collector, docsEnums, sidewaysCollectors);
|
||||
} else {
|
||||
//System.out.println("union");
|
||||
doUnionScoring(collector, docsEnums, sidewaysCollectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,12 +120,14 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
new CountFacetRequest(new CategoryPath("Publish Date"), 10),
|
||||
new CountFacetRequest(new CategoryPath("Author"), 10));
|
||||
|
||||
DrillSideways ds = new DrillSideways(searcher, taxoReader);
|
||||
|
||||
// Simple case: drill-down on a single field; in this
|
||||
// case the drill-sideways + drill-down counts ==
|
||||
// drill-down of just the query:
|
||||
DrillDownQuery ddq = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
|
||||
ddq.add(new CategoryPath("Author", "Lisa"));
|
||||
DrillSidewaysResult r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
DrillSidewaysResult r = ds.search(null, ddq, 10, fsp);
|
||||
|
||||
assertEquals(2, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
|
@ -143,7 +145,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
// just the query:
|
||||
ddq = new DrillDownQuery(fsp.indexingParams);
|
||||
ddq.add(new CategoryPath("Author", "Lisa"));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
|
||||
assertEquals(2, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
|
@ -162,7 +164,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
// but OR of two values
|
||||
ddq = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
|
||||
ddq.add(new CategoryPath("Author", "Lisa"), new CategoryPath("Author", "Bob"));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(3, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
// Publish Date is only drill-down: Lisa and Bob
|
||||
|
@ -177,7 +179,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
ddq = new DrillDownQuery(fsp.indexingParams, new MatchAllDocsQuery());
|
||||
ddq.add(new CategoryPath("Author", "Lisa"));
|
||||
ddq.add(new CategoryPath("Publish Date", "2010"));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(1, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
// Publish Date is drill-sideways + drill-down: Lisa
|
||||
|
@ -195,7 +197,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
ddq.add(new CategoryPath("Author", "Lisa"),
|
||||
new CategoryPath("Author", "Bob"));
|
||||
ddq.add(new CategoryPath("Publish Date", "2010"));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(2, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
// Publish Date is both drill-sideways + drill-down:
|
||||
|
@ -211,7 +213,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
fsp = new FacetSearchParams(
|
||||
new CountFacetRequest(new CategoryPath("Publish Date"), 10),
|
||||
new CountFacetRequest(new CategoryPath("Foobar"), 10));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(0, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
assertEquals("Publish Date:", toString(r.facetResults.get(0)));
|
||||
|
@ -224,7 +226,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
fsp = new FacetSearchParams(
|
||||
new CountFacetRequest(new CategoryPath("Publish Date"), 10),
|
||||
new CountFacetRequest(new CategoryPath("Author"), 10));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(2, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
// Publish Date is only drill-down, and Lisa published
|
||||
|
@ -242,7 +244,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
new CategoryPath("Author", "Tom"));
|
||||
fsp = new FacetSearchParams(
|
||||
new CountFacetRequest(new CategoryPath("Publish Date"), 10));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
assertEquals(2, r.hits.totalHits);
|
||||
assertEquals(1, r.facetResults.size());
|
||||
// Publish Date is only drill-down, and Lisa published
|
||||
|
@ -255,7 +257,7 @@ public class TestDrillSideways extends FacetTestCase {
|
|||
new CountFacetRequest(new CategoryPath("Author"), 10));
|
||||
ddq = new DrillDownQuery(fsp.indexingParams, new TermQuery(new Term("foobar", "baz")));
|
||||
ddq.add(new CategoryPath("Author", "Lisa"));
|
||||
r = new DrillSideways(searcher, taxoReader).search(null, ddq, 10, fsp);
|
||||
r = ds.search(null, ddq, 10, fsp);
|
||||
|
||||
assertEquals(0, r.hits.totalHits);
|
||||
assertEquals(2, r.facetResults.size());
|
||||
|
|
Loading…
Reference in New Issue