Index: lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (revision 1039149) +++ lucene/src/java/org/apache/lucene/search/spans/SpanWeight.java (working copy) @@ -111,7 +111,7 @@ fieldExpl.setDescription("fieldWeight("+field+":"+query.toString(field)+ " in "+doc+"), product of:"); - Explanation tfExpl = ((SpanScorer)scorer(reader, true, false)).explain(doc); + Explanation tfExpl = explainTF(reader, doc); fieldExpl.addDetail(tfExpl); fieldExpl.addDetail(idfExpl); @@ -139,4 +139,9 @@ return result; } + + /** Expert: return an explanation for the TF component of the score. */ + protected Explanation explainTF(IndexReader reader, int doc) throws IOException { + return ((SpanScorer)scorer(reader, true, false)).explain(doc); + } } Index: lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java =================================================================== --- lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java (revision 1039149) +++ lucene/src/java/org/apache/lucene/search/spans/SpanTermQuery.java (working copy) @@ -17,9 +17,16 @@ * limitations under the License. */ +import org.apache.lucene.index.DocsEnum; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.DocsAndPositionsEnum; +import org.apache.lucene.search.Explanation; +import org.apache.lucene.search.Scorer; +import org.apache.lucene.search.Searcher; +import org.apache.lucene.search.SimilarityDelegator; +import org.apache.lucene.search.TermScorer; +import org.apache.lucene.search.Weight; import org.apache.lucene.util.ToStringUtils; import java.io.IOException; @@ -97,4 +104,47 @@ } } } + + @Override + public Weight createWeight(Searcher searcher) throws IOException { + return new SpanWeight(this, searcher) { + @Override + public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer) throws IOException { + DocsEnum docs = reader.termDocsEnum(reader.getDeletedDocs(), + term.field(), + term.bytes()); + + if (docs == null) { + return null; + } + + return new TermScorer(this, docs, new SimilarityDelegator(similarity) { + @Override + public float tf(float freq) { + return super.tf(freq*sloppyFreq(1)); + } + }, reader.norms(term.field())); + } + + @Override + protected Explanation explainTF(IndexReader reader, int doc) throws IOException { + Explanation tfExplanation = new Explanation(); + int tf = 0; + DocsEnum docs = reader.termDocsEnum(reader.getDeletedDocs(), term.field(), term.bytes()); + if (docs != null) { + int newDoc = docs.advance(doc); + if (newDoc == doc) { + tf = docs.freq(); + } + } + + float phraseFreq = similarity.sloppyFreq(1) * tf; + + tfExplanation.setValue(similarity.tf(phraseFreq)); + tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")"); + + return tfExplanation; + } + }; + } } Index: lucene/src/java/org/apache/lucene/search/TermScorer.java =================================================================== --- lucene/src/java/org/apache/lucene/search/TermScorer.java (revision 1039149) +++ lucene/src/java/org/apache/lucene/search/TermScorer.java (working copy) @@ -23,8 +23,9 @@ import org.apache.lucene.search.BooleanClause.Occur; /** Expert: A Scorer for documents matching a Term. + * @lucene.internal */ -final class TermScorer extends Scorer { +public final class TermScorer extends Scorer { private DocsEnum docsEnum; private byte[] norms; private float weightValue; @@ -53,7 +54,7 @@ * @param norms * The field norms of the document fields for the Term. */ - TermScorer(Weight weight, DocsEnum td, Similarity similarity, byte[] norms) { + public TermScorer(Weight weight, DocsEnum td, Similarity similarity, byte[] norms) { super(similarity, weight); this.docsEnum = td;