--- /dev/null
+package org.apache.lucene.search.spans;
+
+/**
+ * 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 java.io.IOException;
+
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Similarity;
+
+/**
+ * Public for extension only.
+ */
+public class SpanScorer extends Scorer {
+ protected Spans spans;
+ protected byte[] norms;
+ protected float value;
+
+ protected boolean more = true;
+
+ protected int doc;
+ protected float freq;
+
+ protected SpanScorer(Spans spans, Weight weight, Similarity similarity, byte[] norms)
+ throws IOException {
+ super(similarity, weight);
+ this.spans = spans;
+ this.norms = norms;
+ this.value = weight.getValue();
+ if (this.spans.next()) {
+ doc = -1;
+ } else {
+ doc = NO_MORE_DOCS;
+ more = false;
+ }
+ }
+
+ @Override
+ public int nextDoc() throws IOException {
+ if (!setFreqCurrentDoc()) {
+ doc = NO_MORE_DOCS;
+ }
+ return doc;
+ }
+
+ @Override
+ public int advance(int target) throws IOException {
+ if (!more) {
+ return doc = NO_MORE_DOCS;
+ }
+ if (spans.doc() < target) { // setFreqCurrentDoc() leaves spans.doc() ahead
+ more = spans.skipTo(target);
+ }
+ if (!setFreqCurrentDoc()) {
+ doc = NO_MORE_DOCS;
+ }
+ return doc;
+ }
+
+ protected boolean setFreqCurrentDoc() throws IOException {
+ if (!more) {
+ return false;
+ }
+ doc = spans.doc();
+ freq = 0.0f;
+ do {
+ int matchLength = spans.end() - spans.start();
+ freq += getSimilarity().sloppyFreq(matchLength);
+ more = spans.next();
+ } while (more && (doc == spans.doc()));
+ return true;
+ }
+
+ @Override
+ public int docID() { return doc; }
+
+ @Override
+ public float score() throws IOException {
+ float raw = getSimilarity().tf(freq) * value; // raw score
+ return norms == null? raw : raw * getSimilarity().decodeNormValue(norms[doc]); // normalize
+ }
+
+ @Override
+ public float freq() throws IOException {
+ return freq;
+ }
+
+ /** This method is no longer an official member of {@link Scorer},
+ * but it is needed by SpanWeight to build an explanation. */
+ protected Explanation explain(final int doc) throws IOException {
+ Explanation tfExplanation = new Explanation();
+
+ int expDoc = advance(doc);
+
+ float phraseFreq = (expDoc == doc) ? freq : 0.0f;
+ tfExplanation.setValue(getSimilarity().tf(phraseFreq));
+ tfExplanation.setDescription("tf(phraseFreq=" + phraseFreq + ")");
+
+ return tfExplanation;
+ }
+
+}