Index: lucene/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java =================================================================== --- lucene/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java (revision 1061618) +++ lucene/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java (working copy) @@ -91,6 +91,10 @@ throw new UnsupportedOperationException(UNSUPPORTED_MSG); } + @Override + public int getLength() { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } } static final class JustCompilePayloadSpans extends Spans { @@ -135,8 +139,8 @@ static final class JustCompileSpanScorer extends SpanScorer { protected JustCompileSpanScorer(Spans spans, Weight weight, - Similarity similarity, byte[] norms) throws IOException { - super(spans, weight, similarity, norms); + Similarity similarity, byte[] norms, int queryLength) throws IOException { + super(spans, weight, similarity, norms, queryLength); } @Override Index: lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced.java =================================================================== --- lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced.java (revision 1061618) +++ lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced.java (working copy) @@ -103,7 +103,7 @@ */ public void testBooleanQueryWithSpanQueries() throws IOException { - doTestBooleanQueryWithSpanQueries(searcher, 0.3884282f); + doTestBooleanQueryWithSpanQueries(searcher, 0.5493205f); } /** Index: lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced2.java =================================================================== --- lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced2.java (revision 1061618) +++ lucene/src/test/org/apache/lucene/search/spans/TestSpansAdvanced2.java (working copy) @@ -88,8 +88,8 @@ final Query spanQuery = new SpanTermQuery(new Term(FIELD_TEXT, "should")); final String[] expectedIds = new String[] {"B", "D", "1", "2", "3", "4", "A"}; - final float[] expectedScores = new float[] {0.625f, 0.45927936f, - 0.35355338f, 0.35355338f, 0.35355338f, 0.35355338f, 0.26516503f,}; + final float[] expectedScores = new float[] {0.88388348f, 0.64951903f, + 0.5f, 0.5f, 0.5f, 0.5f, 0.375f,}; assertHits(searcher2, spanQuery, "single span query", expectedIds, expectedScores); } @@ -109,7 +109,7 @@ final String[] expectedIds = new String[] {"D", "A"}; // these values were pre LUCENE-413 // final float[] expectedScores = new float[] { 0.93163157f, 0.20698164f }; - final float[] expectedScores = new float[] {1.0191123f, 0.93163157f}; + final float[] expectedScores = new float[] {1.4412423f, 1.31752587f}; assertHits(searcher2, query, "multiple different span queries", expectedIds, expectedScores); } @@ -122,6 +122,6 @@ @Override public void testBooleanQueryWithSpanQueries() throws IOException { - doTestBooleanQueryWithSpanQueries(searcher2, 0.73500174f); + doTestBooleanQueryWithSpanQueries(searcher2, 1.03944495f); } } Index: lucene/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java (working copy) @@ -145,7 +145,7 @@ @Override public Scorer scorer(AtomicReaderContext context, ScorerContext scorerContext) throws IOException { return new PayloadNearSpanScorer(query.getSpans(context.reader), this, - similarity, context.reader.norms(query.getField())); + similarity, context.reader.norms(query.getField()), queryLength); } } @@ -155,8 +155,8 @@ private int payloadsSeen; protected PayloadNearSpanScorer(Spans spans, Weight weight, - Similarity similarity, byte[] norms) throws IOException { - super(spans, weight, similarity, norms); + Similarity similarity, byte[] norms, int queryLength) throws IOException { + super(spans, weight, similarity, norms, queryLength); this.spans = spans; } Index: lucene/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java (working copy) @@ -76,7 +76,7 @@ @Override public Scorer scorer(AtomicReaderContext context, ScorerContext scorerContext) throws IOException { return new PayloadTermSpanScorer((TermSpans) query.getSpans(context.reader), - this, similarity, context.reader.norms(query.getField())); + this, similarity, context.reader.norms(query.getField()), queryLength); } protected class PayloadTermSpanScorer extends SpanScorer { @@ -86,8 +86,8 @@ private final TermSpans termSpans; public PayloadTermSpanScorer(TermSpans spans, Weight weight, - Similarity similarity, byte[] norms) throws IOException { - super(spans, weight, similarity, norms); + Similarity similarity, byte[] norms, int queryLength) throws IOException { + super(spans, weight, similarity, norms, queryLength); termSpans = spans; } Index: lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanPayloadCheckQuery.java (working copy) @@ -115,4 +115,9 @@ h ^= Float.floatToRawIntBits(getBoost()) ; return h; } + + @Override + public int getLength() { + return match.getLength(); + } } \ No newline at end of file Index: lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java (working copy) @@ -151,4 +151,9 @@ ^ getField().hashCode() ^ Float.floatToRawIntBits(getBoost()); } + + @Override + public int getLength() { + return maskedQuery.getLength(); + } } Index: lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanNearPayloadCheckQuery.java (working copy) @@ -113,4 +113,9 @@ h ^= Float.floatToRawIntBits(getBoost()); return h; } + + @Override + public int getLength() { + return match.getLength(); + } } \ No newline at end of file Index: lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanNotQuery.java (working copy) @@ -209,4 +209,8 @@ return h; } + @Override + public int getLength() { + return include.getLength(); + } } Index: lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (working copy) @@ -39,7 +39,8 @@ protected Set terms; protected SpanQuery query; private IDFExplanation idfExp; - + protected int queryLength; + public SpanWeight(SpanQuery query, IndexSearcher searcher) throws IOException { this.similarity = searcher.getSimilarity(); @@ -50,6 +51,7 @@ idfExp = similarity.idfExplain(terms, searcher); idf = idfExp.getIdf(); + queryLength = query.getLength(); } @Override @@ -74,7 +76,7 @@ @Override public Scorer scorer(AtomicReaderContext context, ScorerContext scorerContext) throws IOException { return new SpanScorer(query.getSpans(context.reader), this, similarity, context.reader - .norms(query.getField())); + .norms(query.getField()), queryLength); } @Override Index: lucene/src/java/org/apache/lucene/search/spans/SpanScorer.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanScorer.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanScorer.java (working copy) @@ -37,14 +37,16 @@ protected int doc; protected float freq; protected final Similarity similarity; + protected final int queryLength; - protected SpanScorer(Spans spans, Weight weight, Similarity similarity, byte[] norms) + protected SpanScorer(Spans spans, Weight weight, Similarity similarity, byte[] norms, int queryLength) throws IOException { super(weight); this.similarity = similarity; this.spans = spans; this.norms = norms; this.value = weight.getValue(); + this.queryLength = queryLength; if (this.spans.next()) { doc = -1; } else { @@ -82,7 +84,7 @@ doc = spans.doc(); freq = 0.0f; do { - int matchLength = spans.end() - spans.start(); + int matchLength = (spans.end() - spans.start()) - queryLength; freq += similarity.sloppyFreq(matchLength); more = spans.next(); } while (more && (doc == spans.doc())); Index: lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java (working copy) @@ -97,4 +97,9 @@ } } } + + @Override + public int getLength() { + return 1; + } } Index: lucene/src/java/org/apache/lucene/search/spans/SpanQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanQuery.java (working copy) @@ -38,4 +38,13 @@ return new SpanWeight(this, searcher); } + /** + * Returns the length (number of positions) in the query. + *

+ * For example, for a simple Term this is 1. + * For a NEAR of "foo" and "bar" this is 2. + * This is used by SpanScorer to compute the appropriate slop factor, + * so that SpanQueries score consistently with other queries. + */ + public abstract int getLength(); } Index: lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanOrQuery.java (working copy) @@ -258,4 +258,12 @@ }; } + @Override + public int getLength() { + // nocommit: using the max of all the subs for a union? + int max = 0; + for (SpanQuery q : clauses) + max = Math.max(max, q.getLength()); + return max; + } } Index: lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanPositionRangeQuery.java (working copy) @@ -102,4 +102,8 @@ return h; } + @Override + public int getLength() { + return match.getLength(); + } } \ No newline at end of file Index: lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java (working copy) @@ -128,6 +128,11 @@ return query.equals(other.query); } + @Override + public int getLength() { + return 1; + } + /** Abstract class that defines how the query is rewritten. */ public static abstract class SpanRewriteMethod extends MultiTermQuery.RewriteMethod { @Override Index: lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java (revision 1061618) +++ lucene/src/java/org/apache/lucene/search/spans/SpanNearQuery.java (working copy) @@ -188,4 +188,13 @@ result ^= (inOrder ? 0x99AFD3BD : 0); return result; } + + @Override + public int getLength() { + // we are a near: so its the sum of all the subs + int sum = 0; + for (SpanQuery q : clauses) + sum += q.getLength(); + return sum; + } }