| Index: lucene/facet/src/test/org/apache/lucene/facet/search/TestDrillSideways.java |
| =================================================================== |
| --- lucene/facet/src/test/org/apache/lucene/facet/search/TestDrillSideways.java (revision 1470728) |
| +++ lucene/facet/src/test/org/apache/lucene/facet/search/TestDrillSideways.java (working copy) |
| @@ -642,6 +642,7 @@ |
| String[][] drillDowns = new String[numDims][]; |
| |
| int count = 0; |
| + boolean anyMultiValuedDrillDowns = false; |
| while (count < numDrillDown) { |
| int dim = random().nextInt(numDims); |
| if (drillDowns[dim] == null) { |
| @@ -651,6 +652,7 @@ |
| } else { |
| int orCount = _TestUtil.nextInt(random(), 1, Math.min(5, dimValues[dim].length)); |
| drillDowns[dim] = new String[orCount]; |
| + anyMultiValuedDrillDowns |= orCount > 1; |
| for(int i=0;i<orCount;i++) { |
| while (true) { |
| String value = dimValues[dim][random().nextInt(dimValues[dim].length)]; |
| @@ -749,6 +751,22 @@ |
| } |
| }, fsp); |
| |
| + // Also separately verify that DS respects the |
| + // scoreSubDocsAtOnce method, to ensure that all |
| + // subScorers are on the same docID: |
| + if (!anyMultiValuedDrillDowns) { |
| + // Can only do this test when there are no OR'd |
| + // drill-down values, beacuse in that case it's |
| + // easily possible for one of the DD terms to be on |
| + // a future docID: |
| + new DrillSideways(s, tr) { |
| + @Override |
| + protected boolean scoreSubDocsAtOnce() { |
| + return true; |
| + } |
| + }.search(ddq, new AssertingSubDocsAtOnceCollector(), fsp); |
| + } |
| + |
| SimpleFacetResult expected = slowDrillSidewaysSearch(s, requests, docs, contentToken, drillDowns, dimValues, filter); |
| |
| Sort sort = new Sort(new SortField("id", SortField.Type.STRING)); |
| Index: lucene/facet/src/test/org/apache/lucene/facet/search/AssertingSubDocsAtOnceCollector.java |
| =================================================================== |
| --- lucene/facet/src/test/org/apache/lucene/facet/search/AssertingSubDocsAtOnceCollector.java (revision 0) |
| +++ lucene/facet/src/test/org/apache/lucene/facet/search/AssertingSubDocsAtOnceCollector.java (working copy) |
| @@ -0,0 +1,67 @@ |
| +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.util.ArrayList; |
| +import java.util.List; |
| + |
| +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; |
| + |
| +/** Verifies in collect() that all child subScorers are on |
| + * the collected doc. */ |
| +class AssertingSubDocsAtOnceCollector extends Collector { |
| + |
| + // TODO: allow wrapping another Collector |
| + |
| + List<Scorer> allScorers; |
| + |
| + @Override |
| + public void setScorer(Scorer s) { |
| + // Gathers all scorers, including s and "under": |
| + allScorers = new ArrayList<Scorer>(); |
| + allScorers.add(s); |
| + int upto = 0; |
| + while(upto < allScorers.size()) { |
| + s = allScorers.get(upto++); |
| + for (ChildScorer sub : s.getChildren()) { |
| + allScorers.add(sub.child); |
| + } |
| + } |
| + } |
| + |
| + @Override |
| + public void collect(int docID) { |
| + for(Scorer s : allScorers) { |
| + if (docID != s.docID()) { |
| + throw new IllegalStateException("subScorer=" + s + " has docID=" + s.docID() + " != collected docID=" + docID); |
| + } |
| + } |
| + } |
| + |
| + @Override |
| + public void setNextReader(AtomicReaderContext context) { |
| + } |
| + |
| + @Override |
| + public boolean acceptsDocsOutOfOrder() { |
| + return false; |
| + } |
| +} |
| |
| Property changes on: lucene/facet/src/test/org/apache/lucene/facet/search/AssertingSubDocsAtOnceCollector.java |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| ## -0,0 +1 ## |
| +native |
| \ No newline at end of property |
| Index: lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysQuery.java |
| =================================================================== |
| --- lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysQuery.java (revision 1470728) |
| +++ lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysQuery.java (working copy) |
| @@ -39,12 +39,14 @@ |
| final Collector drillDownCollector; |
| final Collector[] drillSidewaysCollectors; |
| final Term[][] drillDownTerms; |
| + final boolean scoreSubDocsAtOnce; |
| |
| - DrillSidewaysQuery(Query baseQuery, Collector drillDownCollector, Collector[] drillSidewaysCollectors, Term[][] drillDownTerms) { |
| + DrillSidewaysQuery(Query baseQuery, Collector drillDownCollector, Collector[] drillSidewaysCollectors, Term[][] drillDownTerms, boolean scoreSubDocsAtOnce) { |
| this.baseQuery = baseQuery; |
| this.drillDownCollector = drillDownCollector; |
| this.drillSidewaysCollectors = drillSidewaysCollectors; |
| this.drillDownTerms = drillDownTerms; |
| + this.scoreSubDocsAtOnce = scoreSubDocsAtOnce; |
| } |
| |
| @Override |
| @@ -65,7 +67,7 @@ |
| if (newQuery == baseQuery) { |
| return this; |
| } else { |
| - return new DrillSidewaysQuery(newQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms); |
| + return new DrillSidewaysQuery(newQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms, scoreSubDocsAtOnce); |
| } |
| } |
| |
| @@ -152,7 +154,7 @@ |
| |
| return new DrillSidewaysScorer(this, context, |
| baseScorer, |
| - drillDownCollector, dims); |
| + drillDownCollector, dims, scoreSubDocsAtOnce); |
| } |
| }; |
| } |
| Index: lucene/facet/src/java/org/apache/lucene/facet/search/DrillSideways.java |
| =================================================================== |
| --- lucene/facet/src/java/org/apache/lucene/facet/search/DrillSideways.java (revision 1470728) |
| +++ lucene/facet/src/java/org/apache/lucene/facet/search/DrillSideways.java (working copy) |
| @@ -209,7 +209,7 @@ |
| drillSidewaysCollectors[idx++] = FacetsCollector.create(getDrillSidewaysAccumulator(dim, new FacetSearchParams(fsp.indexingParams, requests))); |
| } |
| |
| - DrillSidewaysQuery dsq = new DrillSidewaysQuery(baseQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms); |
| + DrillSidewaysQuery dsq = new DrillSidewaysQuery(baseQuery, drillDownCollector, drillSidewaysCollectors, drillDownTerms, scoreSubDocsAtOnce()); |
| |
| searcher.search(dsq, hitCollector); |
| |
| @@ -300,6 +300,19 @@ |
| return FacetsAccumulator.create(fsp, searcher.getIndexReader(), taxoReader); |
| } |
| |
| + /** Override this and return true if your collector |
| + * (e.g., ToParentBlockJoinCollector) expects all |
| + * sub-scorers to be positioned on the document being |
| + * collected. This will cause some performance loss; |
| + * default is false. Note that if you return true from |
| + * this method (in a subclass) be sure your collector |
| + * also returns false from {@link |
| + * Collector#acceptsDocsOutOfOrder}: this will trick |
| + * BooleanQuery into also scoring all subDocs at once. */ |
| + protected boolean scoreSubDocsAtOnce() { |
| + return false; |
| + } |
| + |
| /** Represents the returned result from a drill sideways |
| * search. */ |
| public static class DrillSidewaysResult { |
| Index: lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysScorer.java |
| =================================================================== |
| --- lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysScorer.java (revision 1470728) |
| +++ lucene/facet/src/java/org/apache/lucene/facet/search/DrillSidewaysScorer.java (working copy) |
| @@ -43,17 +43,19 @@ |
| |
| 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) { |
| + DocsEnumsAndFreq[] dims, boolean scoreSubDocsAtOnce) { |
| super(w); |
| this.dims = dims; |
| this.context = context; |
| this.baseScorer = baseScorer; |
| this.drillDownCollector = drillDownCollector; |
| + this.scoreSubDocsAtOnce = scoreSubDocsAtOnce; |
| } |
| |
| @Override |
| @@ -77,7 +79,6 @@ |
| |
| // Position all scorers to their first matching doc: |
| int baseDocID = baseScorer.nextDoc(); |
| - |
| for(DocsEnumsAndFreq dim : dims) { |
| for(DocsEnum docsEnum : dim.docsEnums) { |
| if (docsEnum != null) { |
| @@ -101,7 +102,7 @@ |
| int estBaseHitCount = context.reader().maxDoc() / (1+baseDocID); |
| |
| /* |
| - System.out.println("\nbaseDocID=" + baseDocID + " est=" + estBaseHitCount); |
| + System.out.println("\nbaseDocID=" + baseScorer.docID() + " est=" + estBaseHitCount); |
| System.out.println(" maxDoc=" + context.reader().maxDoc()); |
| System.out.println(" maxFreq=" + maxFreq); |
| System.out.println(" dims[0].freq=" + dims[0].freq); |
| @@ -110,15 +111,22 @@ |
| } |
| */ |
| |
| - if (estBaseHitCount < maxFreq/10) { |
| + //System.out.println("DS score " + scoreSubDocsAtOnce); |
| + if (!scoreSubDocsAtOnce) { |
| + if (estBaseHitCount < maxFreq/10) { |
| + //System.out.println("baseAdvance"); |
| + doBaseAdvanceScoring(collector, docsEnums, sidewaysCollectors); |
| + } else if (numDims > 1 && (dims[1].freq < estBaseHitCount/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 |
| //System.out.println("baseAdvance"); |
| doBaseAdvanceScoring(collector, docsEnums, sidewaysCollectors); |
| - } else if (numDims > 1 && (dims[1].freq < estBaseHitCount/10)) { |
| - //System.out.println("drillDownAdvance"); |
| - doDrillDownAdvanceScoring(collector, docsEnums, sidewaysCollectors); |
| - } else { |
| - //System.out.println("union"); |
| - doUnionScoring(collector, docsEnums, sidewaysCollectors); |
| } |
| } |
| |