001: package org.apache.lucene.index;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import org.apache.lucene.store.IndexInput;
021:
022: import java.io.IOException;
023:
024: final class SegmentTermPositions extends SegmentTermDocs implements
025: TermPositions {
026: private IndexInput proxStream;
027: private int proxCount;
028: private int position;
029:
030: // the current payload length
031: private int payloadLength;
032: // indicates whether the payload of the currend position has
033: // been read from the proxStream yet
034: private boolean needToLoadPayload;
035:
036: // these variables are being used to remember information
037: // for a lazy skip
038: private long lazySkipPointer = -1;
039: private int lazySkipProxCount = 0;
040:
041: SegmentTermPositions(SegmentReader p) {
042: super (p);
043: this .proxStream = null; // the proxStream will be cloned lazily when nextPosition() is called for the first time
044: }
045:
046: final void seek(TermInfo ti, Term term) throws IOException {
047: super .seek(ti, term);
048: if (ti != null)
049: lazySkipPointer = ti.proxPointer;
050:
051: lazySkipProxCount = 0;
052: proxCount = 0;
053: payloadLength = 0;
054: needToLoadPayload = false;
055: }
056:
057: public final void close() throws IOException {
058: super .close();
059: if (proxStream != null)
060: proxStream.close();
061: }
062:
063: public final int nextPosition() throws IOException {
064: // perform lazy skips if neccessary
065: lazySkip();
066: proxCount--;
067: return position += readDeltaPosition();
068: }
069:
070: private final int readDeltaPosition() throws IOException {
071: int delta = proxStream.readVInt();
072: if (currentFieldStoresPayloads) {
073: // if the current field stores payloads then
074: // the position delta is shifted one bit to the left.
075: // if the LSB is set, then we have to read the current
076: // payload length
077: if ((delta & 1) != 0) {
078: payloadLength = proxStream.readVInt();
079: }
080: delta >>>= 1;
081: needToLoadPayload = true;
082: }
083: return delta;
084: }
085:
086: protected final void skippingDoc() throws IOException {
087: // we remember to skip a document lazily
088: lazySkipProxCount += freq;
089: }
090:
091: public final boolean next() throws IOException {
092: // we remember to skip the remaining positions of the current
093: // document lazily
094: lazySkipProxCount += proxCount;
095:
096: if (super .next()) { // run super
097: proxCount = freq; // note frequency
098: position = 0; // reset position
099: return true;
100: }
101: return false;
102: }
103:
104: public final int read(final int[] docs, final int[] freqs) {
105: throw new UnsupportedOperationException(
106: "TermPositions does not support processing multiple documents in one call. Use TermDocs instead.");
107: }
108:
109: /** Called by super.skipTo(). */
110: protected void skipProx(long proxPointer, int payloadLength)
111: throws IOException {
112: // we save the pointer, we might have to skip there lazily
113: lazySkipPointer = proxPointer;
114: lazySkipProxCount = 0;
115: proxCount = 0;
116: this .payloadLength = payloadLength;
117: needToLoadPayload = false;
118: }
119:
120: private void skipPositions(int n) throws IOException {
121: for (int f = n; f > 0; f--) { // skip unread positions
122: readDeltaPosition();
123: skipPayload();
124: }
125: }
126:
127: private void skipPayload() throws IOException {
128: if (needToLoadPayload && payloadLength > 0) {
129: proxStream
130: .seek(proxStream.getFilePointer() + payloadLength);
131: }
132: needToLoadPayload = false;
133: }
134:
135: // It is not always neccessary to move the prox pointer
136: // to a new document after the freq pointer has been moved.
137: // Consider for example a phrase query with two terms:
138: // the freq pointer for term 1 has to move to document x
139: // to answer the question if the term occurs in that document. But
140: // only if term 2 also matches document x, the positions have to be
141: // read to figure out if term 1 and term 2 appear next
142: // to each other in document x and thus satisfy the query.
143: // So we move the prox pointer lazily to the document
144: // as soon as positions are requested.
145: private void lazySkip() throws IOException {
146: if (proxStream == null) {
147: // clone lazily
148: proxStream = (IndexInput) parent.proxStream.clone();
149: }
150:
151: // we might have to skip the current payload
152: // if it was not read yet
153: skipPayload();
154:
155: if (lazySkipPointer != -1) {
156: proxStream.seek(lazySkipPointer);
157: lazySkipPointer = -1;
158: }
159:
160: if (lazySkipProxCount != 0) {
161: skipPositions(lazySkipProxCount);
162: lazySkipProxCount = 0;
163: }
164: }
165:
166: public int getPayloadLength() {
167: return payloadLength;
168: }
169:
170: public byte[] getPayload(byte[] data, int offset)
171: throws IOException {
172: if (!needToLoadPayload) {
173: throw new IOException(
174: "Payload cannot be loaded more than once for the same term position.");
175: }
176:
177: // read payloads lazily
178: byte[] retArray;
179: int retOffset;
180: if (data == null || data.length - offset < payloadLength) {
181: // the array is too small to store the payload data,
182: // so we allocate a new one
183: retArray = new byte[payloadLength];
184: retOffset = 0;
185: } else {
186: retArray = data;
187: retOffset = offset;
188: }
189: proxStream.readBytes(retArray, retOffset, payloadLength);
190: needToLoadPayload = false;
191: return retArray;
192: }
193:
194: public boolean isPayloadAvailable() {
195: return needToLoadPayload && payloadLength > 0;
196: }
197:
198: }
|