add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / java / org / apache / lucene / search / PhraseScorer.java
1 package org.apache.lucene.search;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.IOException;
21
22 /** Expert: Scoring functionality for phrase queries.
23  * <br>A document is considered matching if it contains the phrase-query terms  
24  * at "valid" positions. What "valid positions" are
25  * depends on the type of the phrase query: for an exact phrase query terms are required 
26  * to appear in adjacent locations, while for a sloppy phrase query some distance between 
27  * the terms is allowed. The abstract method {@link #phraseFreq()} of extending classes
28  * is invoked for each document containing all the phrase query terms, in order to 
29  * compute the frequency of the phrase query in that document. A non zero frequency
30  * means a match. 
31  */
32 abstract class PhraseScorer extends Scorer {
33   protected byte[] norms;
34   protected float value;
35
36   private boolean firstTime = true;
37   private boolean more = true;
38   protected PhraseQueue pq;
39   protected PhrasePositions first, last;
40
41   private float freq; //phrase frequency in current doc as computed by phraseFreq().
42
43   PhraseScorer(Weight weight, PhraseQuery.PostingsAndFreq[] postings,
44       Similarity similarity, byte[] norms) {
45     super(similarity, weight);
46     this.norms = norms;
47     this.value = weight.getValue();
48
49     // convert tps to a list of phrase positions.
50     // note: phrase-position differs from term-position in that its position
51     // reflects the phrase offset: pp.pos = tp.pos - offset.
52     // this allows to easily identify a matching (exact) phrase 
53     // when all PhrasePositions have exactly the same position.
54     for (int i = 0; i < postings.length; i++) {
55       PhrasePositions pp = new PhrasePositions(postings[i].postings, postings[i].position, i);
56       if (last != null) {                         // add next to end of list
57         last.next = pp;
58       } else {
59         first = pp;
60       }
61       last = pp;
62     }
63
64     pq = new PhraseQueue(postings.length);             // construct empty pq
65     first.doc = -1;
66   }
67
68   @Override
69   public int docID() { return first.doc; }
70
71   @Override
72   public int nextDoc() throws IOException {
73     if (firstTime) {
74       init();
75       firstTime = false;
76     } else if (more) {
77       more = last.next();                         // trigger further scanning
78     }
79     if (!doNext()) {
80       first.doc = NO_MORE_DOCS;
81     }
82     return first.doc;
83   }
84   
85   // next without initial increment
86   private boolean doNext() throws IOException {
87     while (more) {
88       while (more && first.doc < last.doc) {      // find doc w/ all the terms
89         more = first.skipTo(last.doc);            // skip first upto last
90         firstToLast();                            // and move it to the end
91       }
92
93       if (more) {
94         // found a doc with all of the terms
95         freq = phraseFreq();                      // check for phrase
96         if (freq == 0.0f)                         // no match
97           more = last.next();                     // trigger further scanning
98         else
99           return true;                            // found a match
100       }
101     }
102     return false;                                 // no more matches
103   }
104
105   @Override
106   public float score() throws IOException {
107     //System.out.println("scoring " + first.doc);
108     float raw = getSimilarity().tf(freq) * value; // raw score
109     return norms == null ? raw : raw * getSimilarity().decodeNormValue(norms[first.doc]); // normalize
110   }
111
112   @Override
113   public int advance(int target) throws IOException {
114     firstTime = false;
115     for (PhrasePositions pp = first; more && pp != null; pp = pp.next) {
116       more = pp.skipTo(target);
117     }
118     if (more) {
119       sort();                                     // re-sort
120     }
121     if (!doNext()) {
122       first.doc = NO_MORE_DOCS;
123     }
124     return first.doc;
125   }
126   
127   /**
128    * phrase frequency in current doc as computed by phraseFreq().
129    */
130   @Override
131   public final float freq() {
132     return freq;
133   }
134
135   /**
136    * For a document containing all the phrase query terms, compute the
137    * frequency of the phrase in that document. 
138    * A non zero frequency means a match.
139    * <br>Note, that containing all phrase terms does not guarantee a match - they have to be found in matching locations.  
140    * @return frequency of the phrase in current doc, 0 if not found. 
141    */
142   protected abstract float phraseFreq() throws IOException;
143
144   private void init() throws IOException {
145     for (PhrasePositions pp = first; more && pp != null; pp = pp.next) {
146       more = pp.next();
147     }
148     if (more) {
149       sort();
150     }
151   }
152   
153   private void sort() {
154     pq.clear();
155     for (PhrasePositions pp = first; pp != null; pp = pp.next) {
156       pq.add(pp);
157     }
158     pqToList();
159   }
160
161   protected final void pqToList() {
162     last = first = null;
163     while (pq.top() != null) {
164       PhrasePositions pp = pq.pop();
165       if (last != null) {                         // add next to end of list
166         last.next = pp;
167       } else
168         first = pp;
169       last = pp;
170       pp.next = null;
171     }
172   }
173
174   protected final void firstToLast() {
175     last.next = first;                    // move first to end of list
176     last = first;
177     first = first.next;
178     last.next = null;
179   }
180
181   @Override
182   public String toString() { return "scorer(" + weight + ")"; }
183  
184 }