Index: lucene/core/src/java/org/apache/lucene/search/BooleanScorer2.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/BooleanScorer2.java (revision 1574538)
+++ lucene/core/src/java/org/apache/lucene/search/BooleanScorer2.java (working copy)
@@ -171,7 +171,7 @@
@Override
public float score() throws IOException {
coordinator.nrMatchers += super.nrMatchers;
- return (float) super.score;
+ return super.score();
}
};
}
Index: lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java (revision 1574538)
+++ lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java (working copy)
@@ -27,8 +27,8 @@
/** The number of subscorers that provide the current match. */
protected int nrMatchers = -1;
- protected double score = Float.NaN;
private final float[] coord;
+ private final int[] matches;
/** Construct a DisjunctionScorer.
* @param weight The weight to be used.
@@ -41,6 +41,7 @@
if (numScorers <= 1) {
throw new IllegalArgumentException("There must be at least 2 subScorers");
}
+ matches = new int[numScorers];
this.coord = coord;
}
@@ -49,23 +50,19 @@
final Scorer sub = subScorers[0];
doc = sub.docID();
if (doc != NO_MORE_DOCS) {
- score = sub.score();
+ matches[0] = 0;
nrMatchers = 1;
- countMatches(1);
- countMatches(2);
+ gatherMatches(1);
+ gatherMatches(2);
}
}
- // TODO: this currently scores, but so did the previous impl
// TODO: remove recursion.
- // TODO: if we separate scoring, out of here,
- // then change freq() to just always compute it from scratch
- private void countMatches(int root) throws IOException {
+ private void gatherMatches(int root) throws IOException {
if (root < numScorers && subScorers[root].docID() == doc) {
- nrMatchers++;
- score += subScorers[root].score();
- countMatches((root<<1)+1);
- countMatches((root<<1)+2);
+ matches[nrMatchers++] = root;
+ gatherMatches((root<<1)+1);
+ gatherMatches((root<<1)+2);
}
}
@@ -74,7 +71,15 @@
*/
@Override
public float score() throws IOException {
- return (float)score * coord[nrMatchers];
+ double score = 0.0;
+ for(int i=0;isims. */
+ public SwitchingSimilarity(Similarity... sims) {
+ this.sims = sims;
+ }
+
+ @Override
+ public long computeNorm(FieldInvertState state) {
+ return sims[0].computeNorm(state);
+ }
+
+ @Override
+ public SimWeight computeWeight(float queryBoost, CollectionStatistics collectionStats, TermStatistics... termStats) {
+ SimWeight subStats[] = new SimWeight[sims.length];
+ for (int i = 0; i < subStats.length; i++) {
+ subStats[i] = sims[i].computeWeight(queryBoost, collectionStats, termStats);
+ }
+ return new SwitchingStats(subStats);
+ }
+
+ @Override
+ public SimScorer simScorer(SimWeight stats, AtomicReaderContext context) throws IOException {
+ SimScorer subScorers[] = new SimScorer[sims.length];
+ for (int i = 0; i < subScorers.length; i++) {
+ subScorers[i] = sims[i].simScorer(((SwitchingStats)stats).subStats[i], context);
+ }
+ return new SwitchingSimScorer(subScorers);
+ }
+
+ /** Moves to the next sub-scorer. */
+ public void switchScorer() {
+ scorerIndex++;
+ if (scorerIndex == sims.length) {
+ scorerIndex = 0;
+ }
+ }
+
+ public class SwitchingSimScorer extends SimScorer {
+ private final SimScorer subScorers[];
+
+ SwitchingSimScorer(SimScorer subScorers[]) {
+ this.subScorers = subScorers;
+ }
+
+ @Override
+ public float score(int doc, float freq) {
+ return subScorers[scorerIndex].score(doc, freq);
+ }
+
+ @Override
+ public Explanation explain(int doc, Explanation freq) {
+ return subScorers[scorerIndex].explain(doc, freq);
+ }
+
+ @Override
+ public float computeSlopFactor(int distance) {
+ return subScorers[0].computeSlopFactor(distance);
+ }
+
+ @Override
+ public float computePayloadFactor(int doc, int start, int end, BytesRef payload) {
+ return subScorers[0].computePayloadFactor(doc, start, end, payload);
+ }
+ }
+
+ static class SwitchingStats extends SimWeight {
+ final SimWeight subStats[];
+
+ SwitchingStats(SimWeight subStats[]) {
+ this.subStats = subStats;
+ }
+
+ @Override
+ public float getValueForNormalization() {
+ float sum = 0.0f;
+ for (SimWeight stat : subStats) {
+ sum += stat.getValueForNormalization();
+ }
+ return sum / subStats.length;
+ }
+
+ @Override
+ public void normalize(float queryNorm, float topLevelBoost) {
+ for (SimWeight stat : subStats) {
+ stat.normalize(queryNorm, topLevelBoost);
+ }
+ }
+ }
+}
Property changes on: lucene/misc/src/java/org/apache/lucene/search/SwitchingSimilarity.java
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Index: lucene/misc/src/test/org/apache/lucene/search/TestSwitchingSimilarityCollector.java
===================================================================
--- lucene/misc/src/test/org/apache/lucene/search/TestSwitchingSimilarityCollector.java (revision 0)
+++ lucene/misc/src/test/org/apache/lucene/search/TestSwitchingSimilarityCollector.java (working copy)
@@ -0,0 +1,114 @@
+package org.apache.lucene.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 org.apache.lucene.analysis.MockAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.RandomIndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.similarities.BM25Similarity;
+import org.apache.lucene.search.similarities.DefaultSimilarity;
+import org.apache.lucene.search.similarities.LMJelinekMercerSimilarity;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestSwitchingSimilarityCollector extends LuceneTestCase {
+
+ public void testBasic() throws Exception {
+ Directory dir = newDirectory();
+
+ IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT,
+ new MockAnalyzer(random()));
+ iwc.setSimilarity(new SwitchingSimilarity(new DefaultSimilarity(),
+ new BM25Similarity()));
+ RandomIndexWriter w = new RandomIndexWriter(random(), dir, iwc);
+
+ Document doc = new Document();
+ doc.add(newTextField("field", "a x", Field.Store.NO));
+ w.addDocument(doc);
+
+ doc.add(newTextField("field", "a y", Field.Store.NO));
+ w.addDocument(doc);
+
+ doc.add(newTextField("field", "b x", Field.Store.NO));
+ w.addDocument(doc);
+
+ IndexReader r = w.getReader();
+ w.close();
+
+ // TermQuery
+ runQuery(r, new TermQuery(new Term("field", "a")));
+
+ // BooleanQuery
+ BooleanQuery bq = new BooleanQuery();
+ bq.add(new TermQuery(new Term("field", "a")), BooleanClause.Occur.SHOULD);
+ bq.add(new TermQuery(new Term("field", "y")), BooleanClause.Occur.SHOULD);
+ runQuery(r, bq);
+
+ r.close();
+ dir.close();
+ }
+
+ private void runQuery(IndexReader r, Query q) throws Exception {
+ if (VERBOSE) {
+ System.out.println("\nTEST: run query=" + q);
+ }
+
+ TopScoreDocCollector c1 = TopScoreDocCollector.create(10, true);
+ TopScoreDocCollector c2 = TopScoreDocCollector.create(10, true);
+ TopScoreDocCollector c3 = TopScoreDocCollector.create(10, true);
+ SwitchingSimilarity sim = new SwitchingSimilarity(new DefaultSimilarity(),
+ new BM25Similarity(),
+ new LMJelinekMercerSimilarity(0.3f));
+
+ // NOTE: we must make a new searcher for every query,
+ // because SwitchingSimilarity has per-hit state. This
+ // is fine (it's cheap: basically just wraps the
+ // reader):
+ IndexSearcher s = newSearcher(r);
+ s.setSimilarity(sim);
+ s.search(q,
+ new SwitchingSimilarityCollector(sim, c1, c2, c3));
+
+ TopDocs hits1 = c1.topDocs();
+ TopDocs hits2 = c2.topDocs();
+ TopDocs hits3 = c3.topDocs();
+
+ assertEquals(hits1.totalHits, hits2.totalHits);
+ assertEquals(hits1.totalHits, hits3.totalHits);
+ assertEquals(hits1.scoreDocs.length, hits2.scoreDocs.length);
+ assertEquals(hits1.scoreDocs.length, hits3.scoreDocs.length);
+ boolean sawDifference = false;
+ for(int i=0;i