Index: lucene/core/src/test/org/apache/lucene/search/intervals/TestIntervalScoring.java =================================================================== --- lucene/core/src/test/org/apache/lucene/search/intervals/TestIntervalScoring.java (revision 0) +++ lucene/core/src/test/org/apache/lucene/search/intervals/TestIntervalScoring.java (revision 0) @@ -0,0 +1,93 @@ +package org.apache.lucene.search.intervals; + +/* + * 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.TextField; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.RegexpQuery; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TopDocs; +import org.apache.lucene.search.similarities.DefaultSimilarity; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; +import org.junit.Assert; + +import java.io.IOException; + +public class TestIntervalScoring extends LuceneTestCase { + + private IndexSearcher searcher; + private IndexReader reader; + private Directory directory; + + public static final String field = "field"; + + @Override + public void setUp() throws Exception { + super.setUp(); + directory = newDirectory(); + RandomIndexWriter writer = new RandomIndexWriter(random(), directory, + newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())) + .setMergePolicy(newLogMergePolicy())); + for (int i = 0; i < docFields.length; i++) { + Document doc = new Document(); + doc.add(newField(field, docFields[i], TextField.TYPE_STORED)); + writer.addDocument(doc); + } + writer.forceMerge(1); + reader = writer.getReader(); + writer.close(); + searcher = newSearcher(reader); + searcher.setSimilarity(new DefaultSimilarity()); + } + + @Override + public void tearDown() throws Exception { + reader.close(); + directory.close(); + super.tearDown(); + } + + private String[] docFields = { + "Should we, could we, would we?", + "It should - would it?", + "It shouldn't", + "Should we, should we, should we" + }; + + public void testOrderedNearQueryScoring() throws IOException { + OrderedNearQuery q = new OrderedNearQuery(10, new TermQuery(new Term(field, "should")), + new TermQuery(new Term(field, "would"))); + TopDocs docs = searcher.search(q, 10); + Assert.assertEquals(docs.scoreDocs[0].doc, 1); + Assert.assertEquals(docs.scoreDocs[1].doc, 0); + } + + public void testEmptyMultiTermQueryScoring() throws IOException { + OrderedNearQuery q = new OrderedNearQuery(10, new RegexpQuery(new Term(field, "bar.*")), + new RegexpQuery(new Term(field, "foo.*"))); + TopDocs docs = searcher.search(q, 10); + Assert.assertEquals(docs.totalHits, 0); + } + +} Property changes on: lucene/core/src/test/org/apache/lucene/search/intervals/TestIntervalScoring.java ___________________________________________________________________ Added: svn:eol-style + native Index: lucene/core/src/java/org/apache/lucene/search/intervals/IntervalFilterQuery.java =================================================================== --- lucene/core/src/java/org/apache/lucene/search/intervals/IntervalFilterQuery.java (revision 1405439) +++ lucene/core/src/java/org/apache/lucene/search/intervals/IntervalFilterQuery.java (working copy) @@ -20,17 +20,21 @@ import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; +import org.apache.lucene.index.TermContext; import org.apache.lucene.search.ComplexExplanation; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.TermStatistics; import org.apache.lucene.search.Weight; import org.apache.lucene.search.Weight.PostingFeatures; +import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.util.Bits; import java.io.IOException; import java.util.Set; +import java.util.TreeSet; /** * A Query that filters the results of an inner {@link Query} using an @@ -81,22 +85,43 @@ @Override public Weight createWeight(IndexSearcher searcher) throws IOException { - return new PositionFilterWeight(inner.createWeight(searcher)); + return new PositionFilterWeight(inner.createWeight(searcher), searcher); } class PositionFilterWeight extends Weight { private final Weight other; + private final Similarity similarity; + private final Similarity.SimWeight stats; - public PositionFilterWeight(Weight other) { + public PositionFilterWeight(Weight other, IndexSearcher searcher) throws IOException { this.other = other; + this.similarity = searcher.getSimilarity(); + this.stats = getSimWeight(other.getQuery(), searcher); } + private Similarity.SimWeight getSimWeight(Query query, IndexSearcher searcher) throws IOException { + TreeSet terms = new TreeSet(); + query.extractTerms(terms); + int i = 0; + TermStatistics[] termStats = new TermStatistics[terms.size()]; + for (Term term : terms) { + TermContext state = TermContext.build(searcher.getTopReaderContext(), term, true); + termStats[i] = searcher.termStatistics(term, state); + i++; + } + final String field = terms.first().field(); // nocommit - should we be checking all filtered terms + // are on the same field? + return similarity.computeWeight(query.getBoost(), searcher.collectionStatistics(field), termStats); + + } + @Override public Explanation explain(AtomicReaderContext context, int doc) throws IOException { Scorer scorer = scorer(context, true, false, PostingFeatures.POSITIONS, context.reader().getLiveDocs()); + // nocommit - need to add in IntervalFilter details... if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { @@ -113,7 +138,8 @@ flags = flags == PostingFeatures.DOCS_AND_FREQS ? PostingFeatures.POSITIONS : flags; ScorerFactory factory = new ScorerFactory(other, context, topScorer, flags, acceptDocs); final Scorer scorer = factory.scorer(); - return scorer == null ? null : new PositionFilterScorer(this, scorer, factory); + Similarity.SloppySimScorer docScorer = similarity.sloppySimScorer(stats, context); + return scorer == null ? null : new PositionFilterScorer(this, scorer, factory, docScorer); } @Override @@ -123,12 +149,13 @@ @Override public float getValueForNormalization() throws IOException { - return other.getValueForNormalization(); + return stats == null ? 1.0f : stats.getValueForNormalization(); } @Override public void normalize(float norm, float topLevelBoost) { - other.normalize(norm, topLevelBoost); + if (stats != null) + stats.normalize(norm, topLevelBoost); } } @@ -155,20 +182,25 @@ } final class PositionFilterScorer extends Scorer { + private final Scorer other; private IntervalIterator filter; private Interval current; private final ScorerFactory factory; - public PositionFilterScorer(Weight weight, Scorer other, ScorerFactory factory) throws IOException { + private final Similarity.SloppySimScorer docScorer; + + public PositionFilterScorer(Weight weight, Scorer other, ScorerFactory factory, + Similarity.SloppySimScorer docScorer) throws IOException { super(weight); this.other = other; this.factory = factory; this.filter = IntervalFilterQuery.this.filter.filter(false, other.intervals(false)); + this.docScorer = docScorer; } @Override public float score() throws IOException { - return other.score(); + return docScorer.score(docID(), freq()); } @Override @@ -281,7 +313,13 @@ @Override public float freq() throws IOException { - return other.freq(); + float freq = 0.0f; + do { + int d = filter.matchDistance(); + freq += docScorer.computeSlopFactor(d); + } + while (filter.next() != null); + return freq; } }