@Override public Explanation explain(AtomicReaderContext context, int doc) throws IOException { Scorer scorer = scorer(context, true, false, context.reader().getLiveDocs()); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { float freq = scorer.freq(); SloppySimScorer docScorer = similarity.sloppySimScorer(stats, context); ComplexExplanation result = new ComplexExplanation(); result.setDescription( "weight(" + getQuery() + " in " + doc + ") [" + similarity.getClass().getSimpleName() + "], result of:"); Explanation scoreExplanation = docScorer.explain(doc, new Explanation(freq, "phraseFreq=" + freq)); result.addDetail(scoreExplanation); result.setValue(scoreExplanation.getValue()); result.setMatch(true); return result; } } return new ComplexExplanation(false, 0.0f, "no matching term"); }
@Override public int advance(int target) throws IOException { int doc = subQueryScorer.advance(target); if (doc != NO_MORE_DOCS) { for (int i = 0; i < valSrcScorers.length; i++) { valSrcScorers[i].advance(doc); } } return doc; }
@Override public Explanation explain(AtomicReaderContext context, int doc) throws IOException { Scorer scorer = scorer(context, context.reader().getLiveDocs()); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { float score = scorer.score(); ComplexExplanation result = new ComplexExplanation(); result.setDescription("ImageHashLimitQuery, product of:"); result.setValue(score); if (getBoost() != 1.0f) { result.addDetail(new Explanation(getBoost(), "boost")); score = score / getBoost(); } result.addDetail(new Explanation(score, "image score (1/distance)")); result.setMatch(true); return result; } } return new ComplexExplanation(false, 0.0f, "no matching term"); }
@Override public int advance(int target) throws IOException { return scorer.advance(target); }
/** not a direct test of NearSpans, but a demonstration of how/when this causes problems */ public void testSpanNearScorerSkipTo1() throws Exception { SpanNearQuery q = makeQuery(); Weight w = q.weight(searcher); Scorer s = w.scorer(searcher.getIndexReader(), true, false); assertEquals(1, s.advance(1)); }
/** Used when drill downs are highly constraining vs baseQuery. */ private void doDrillDownAdvanceScoring( Bits acceptDocs, LeafCollector collector, DocsAndCost[] dims) throws IOException { final int maxDoc = context.reader().maxDoc(); final int numDims = dims.length; // if (DEBUG) { // System.out.println(" doDrillDownAdvanceScoring"); // } // TODO: maybe a class like BS, instead of parallel arrays int[] filledSlots = new int[CHUNK]; int[] docIDs = new int[CHUNK]; float[] scores = new float[CHUNK]; int[] missingDims = new int[CHUNK]; int[] counts = new int[CHUNK]; docIDs[0] = -1; int nextChunkStart = CHUNK; final FixedBitSet seen = new FixedBitSet(CHUNK); while (true) { // if (DEBUG) { // System.out.println("\ncycle nextChunkStart=" + nextChunkStart + " docIds[0]=" + // docIDs[0]); // } // First dim: // if (DEBUG) { // System.out.println(" dim0"); // } DocsAndCost dc = dims[0]; int docID = dc.approximation.docID(); while (docID < nextChunkStart) { if (acceptDocs == null || acceptDocs.get(docID)) { int slot = docID & MASK; if (docIDs[slot] != docID && (dc.twoPhase == null || dc.twoPhase.matches())) { seen.set(slot); // Mark slot as valid: // if (DEBUG) { // System.out.println(" set docID=" + docID + " id=" + // context.reader().document(docID).get("id")); // } docIDs[slot] = docID; missingDims[slot] = 1; counts[slot] = 1; } } docID = dc.approximation.nextDoc(); } // Second dim: // if (DEBUG) { // System.out.println(" dim1"); // } dc = dims[1]; docID = dc.approximation.docID(); while (docID < nextChunkStart) { if (acceptDocs == null || acceptDocs.get(docID) && (dc.twoPhase == null || dc.twoPhase.matches())) { int slot = docID & MASK; if (docIDs[slot] != docID) { // Mark slot as valid: seen.set(slot); // if (DEBUG) { // System.out.println(" set docID=" + docID + " missingDim=0 id=" + // context.reader().document(docID).get("id")); // } docIDs[slot] = docID; missingDims[slot] = 0; counts[slot] = 1; } else { // TODO: single-valued dims will always be true // below; we could somehow specialize if (missingDims[slot] >= 1) { missingDims[slot] = 2; counts[slot] = 2; // if (DEBUG) { // System.out.println(" set docID=" + docID + " missingDim=2 id=" + // context.reader().document(docID).get("id")); // } } else { counts[slot] = 1; // if (DEBUG) { // System.out.println(" set docID=" + docID + " missingDim=" + missingDims[slot] + // " id=" + context.reader().document(docID).get("id")); // } } } } docID = dc.approximation.nextDoc(); } // After this we can "upgrade" to conjunction, because // any doc not seen by either dim 0 or dim 1 cannot be // a hit or a near miss: // if (DEBUG) { // System.out.println(" baseScorer"); // } // Fold in baseScorer, using advance: int filledCount = 0; int slot0 = 0; while (slot0 < CHUNK && (slot0 = seen.nextSetBit(slot0)) != DocIdSetIterator.NO_MORE_DOCS) { int ddDocID = docIDs[slot0]; assert ddDocID != -1; int baseDocID = baseScorer.docID(); if (baseDocID < ddDocID) { baseDocID = baseScorer.advance(ddDocID); } if (baseDocID == ddDocID) { // if (DEBUG) { // System.out.println(" keep docID=" + ddDocID + " id=" + // context.reader().document(ddDocID).get("id")); // } scores[slot0] = baseScorer.score(); filledSlots[filledCount++] = slot0; counts[slot0]++; } else { // if (DEBUG) { // System.out.println(" no docID=" + ddDocID + " id=" + // context.reader().document(ddDocID).get("id")); // } docIDs[slot0] = -1; // TODO: we could jump slot0 forward to the // baseDocID ... but we'd need to set docIDs for // intervening slots to -1 } slot0++; } seen.clear(0, CHUNK); if (filledCount == 0) { if (nextChunkStart >= maxDoc) { break; } nextChunkStart += CHUNK; continue; } // TODO: factor this out & share w/ union scorer, // except we start from dim=2 instead: for (int dim = 2; dim < numDims; dim++) { // if (DEBUG) { // System.out.println(" dim=" + dim + " [" + dims[dim].dim + "]"); // } dc = dims[dim]; docID = dc.approximation.docID(); while (docID < nextChunkStart) { int slot = docID & MASK; if (docIDs[slot] == docID && counts[slot] >= dim && (dc.twoPhase == null || dc.twoPhase.matches())) { // TODO: single-valued dims will always be true // below; we could somehow specialize if (missingDims[slot] >= dim) { // if (DEBUG) { // System.out.println(" set docID=" + docID + " count=" + (dim+2)); // } missingDims[slot] = dim + 1; counts[slot] = dim + 2; } else { // if (DEBUG) { // System.out.println(" set docID=" + docID + " missing count=" + (dim+1)); // } counts[slot] = dim + 1; } } // TODO: sometimes use advance? docID = dc.approximation.nextDoc(); } } // Collect: // if (DEBUG) { // System.out.println(" now collect: " + filledCount + " hits"); // } for (int i = 0; i < filledCount; i++) { int slot = filledSlots[i]; collectDocID = docIDs[slot]; collectScore = scores[slot]; // if (DEBUG) { // System.out.println(" docID=" + docIDs[slot] + " count=" + counts[slot]); // } if (counts[slot] == 1 + numDims) { collectHit(collector, dims); } else if (counts[slot] == numDims) { collectNearMiss(dims[missingDims[slot]].sidewaysLeafCollector); } } if (nextChunkStart >= maxDoc) { break; } nextChunkStart += CHUNK; } }