pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / index / SegmentTermPositions.java
1 package org.apache.lucene.index;
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 org.apache.lucene.index.FieldInfo.IndexOptions;
21 import org.apache.lucene.store.IndexInput;
22
23 import java.io.IOException;
24
25 final class SegmentTermPositions
26 extends SegmentTermDocs implements TermPositions {
27   private IndexInput proxStream;
28   private int proxCount;
29   private int position;
30   
31   // the current payload length
32   private int payloadLength;
33   // indicates whether the payload of the current position has
34   // been read from the proxStream yet
35   private boolean needToLoadPayload;
36   
37   // these variables are being used to remember information
38   // for a lazy skip
39   private long lazySkipPointer = -1;
40   private int lazySkipProxCount = 0;
41   
42   SegmentTermPositions(SegmentReader p) {
43     super(p);
44     this.proxStream = null;  // the proxStream will be cloned lazily when nextPosition() is called for the first time
45   }
46
47   @Override
48   final void seek(TermInfo ti, Term term) throws IOException {
49     super.seek(ti, term);
50     if (ti != null)
51       lazySkipPointer = ti.proxPointer;
52     
53     lazySkipProxCount = 0;
54     proxCount = 0;
55     payloadLength = 0;
56     needToLoadPayload = false;
57   }
58
59   @Override
60   public final void close() throws IOException {
61     super.close();
62     if (proxStream != null) proxStream.close();
63   }
64
65   public final int nextPosition() throws IOException {
66     if (indexOptions != IndexOptions.DOCS_AND_FREQS_AND_POSITIONS)
67       // This field does not store positions, payloads
68       return 0;
69     // perform lazy skips if necessary
70     lazySkip();
71     proxCount--;
72     return position += readDeltaPosition();
73   }
74
75   private final int readDeltaPosition() throws IOException {
76     int delta = proxStream.readVInt();
77     if (currentFieldStoresPayloads) {
78       // if the current field stores payloads then
79       // the position delta is shifted one bit to the left.
80       // if the LSB is set, then we have to read the current
81       // payload length
82       if ((delta & 1) != 0) {
83         payloadLength = proxStream.readVInt();
84       } 
85       delta >>>= 1;
86       needToLoadPayload = true;
87     }
88     return delta;
89   }
90   
91   @Override
92   protected final void skippingDoc() throws IOException {
93     // we remember to skip a document lazily
94     lazySkipProxCount += freq;
95   }
96
97   @Override
98   public final boolean next() throws IOException {
99     // we remember to skip the remaining positions of the current
100     // document lazily
101     lazySkipProxCount += proxCount;
102     
103     if (super.next()) {               // run super
104       proxCount = freq;               // note frequency
105       position = 0;               // reset position
106       return true;
107     }
108     return false;
109   }
110
111   @Override
112   public final int read(final int[] docs, final int[] freqs) {
113     throw new UnsupportedOperationException("TermPositions does not support processing multiple documents in one call. Use TermDocs instead.");
114   }
115
116
117   /** Called by super.skipTo(). */
118   @Override
119   protected void skipProx(long proxPointer, int payloadLength) throws IOException {
120     // we save the pointer, we might have to skip there lazily
121     lazySkipPointer = proxPointer;
122     lazySkipProxCount = 0;
123     proxCount = 0;
124     this.payloadLength = payloadLength;
125     needToLoadPayload = false;
126   }
127
128   private void skipPositions(int n) throws IOException {
129     assert indexOptions == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS;
130     for (int f = n; f > 0; f--) {        // skip unread positions
131       readDeltaPosition();
132       skipPayload();
133     }      
134   }
135   
136   private void skipPayload() throws IOException {
137     if (needToLoadPayload && payloadLength > 0) {
138       proxStream.seek(proxStream.getFilePointer() + payloadLength);
139     }
140     needToLoadPayload = false;
141   }
142
143   // It is not always necessary to move the prox pointer
144   // to a new document after the freq pointer has been moved.
145   // Consider for example a phrase query with two terms:
146   // the freq pointer for term 1 has to move to document x
147   // to answer the question if the term occurs in that document. But
148   // only if term 2 also matches document x, the positions have to be
149   // read to figure out if term 1 and term 2 appear next
150   // to each other in document x and thus satisfy the query.
151   // So we move the prox pointer lazily to the document
152   // as soon as positions are requested.
153   private void lazySkip() throws IOException {
154     if (proxStream == null) {
155       // clone lazily
156       proxStream = (IndexInput) parent.core.proxStream.clone();
157     }
158     
159     // we might have to skip the current payload
160     // if it was not read yet
161     skipPayload();
162       
163     if (lazySkipPointer != -1) {
164       proxStream.seek(lazySkipPointer);
165       lazySkipPointer = -1;
166     }
167      
168     if (lazySkipProxCount != 0) {
169       skipPositions(lazySkipProxCount);
170       lazySkipProxCount = 0;
171     }
172   }
173   
174   public int getPayloadLength() {
175     return payloadLength;
176   }
177
178   public byte[] getPayload(byte[] data, int offset) throws IOException {
179     if (!needToLoadPayload) {
180       throw new IOException("Either no payload exists at this term position or an attempt was made to load it more than once.");
181     }
182
183     // read payloads lazily
184     byte[] retArray;
185     int retOffset;
186     if (data == null || data.length - offset < payloadLength) {
187       // the array is too small to store the payload data,
188       // so we allocate a new one
189       retArray = new byte[payloadLength];
190       retOffset = 0;
191     } else {
192       retArray = data;
193       retOffset = offset;
194     }
195     proxStream.readBytes(retArray, retOffset, payloadLength);
196     needToLoadPayload = false;
197     return retArray;
198   }
199
200   public boolean isPayloadAvailable() {
201     return needToLoadPayload && payloadLength > 0;
202   }
203
204 }