~slub.team/goobi-indexserver/3.x

« back to all changes in this revision

Viewing changes to lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java

  • Committer: Sebastian Meyer
  • Date: 2012-08-03 09:12:40 UTC
  • Revision ID: sebastian.meyer@slub-dresden.de-20120803091240-x6861b0vabq1xror
Remove Lucene and Solr source code and add patches instead
Fix Bug #985487: Auto-suggestion for the search interface

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.apache.lucene.util.fst;
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.util.ArrayUtil;
21
 
import org.apache.lucene.util.RamUsageEstimator;
22
 
 
23
 
import java.io.IOException;
24
 
 
25
 
/** Can next() and advance() through the terms in an FST
26
 
 *
27
 
  * @lucene.experimental
28
 
*/
29
 
 
30
 
abstract class FSTEnum<T> {
31
 
  protected final FST<T> fst;
32
 
 
33
 
  @SuppressWarnings("unchecked") protected FST.Arc<T>[] arcs = new FST.Arc[10];
34
 
  // outputs are cumulative
35
 
  @SuppressWarnings("unchecked") protected T[] output = (T[]) new Object[10];
36
 
 
37
 
  protected final T NO_OUTPUT;
38
 
  protected final FST.Arc<T> scratchArc = new FST.Arc<T>();
39
 
 
40
 
  protected int upto;
41
 
  protected int targetLength;
42
 
 
43
 
  /** doFloor controls the behavior of advance: if it's true
44
 
   *  doFloor is true, advance positions to the biggest
45
 
   *  term before target.  */
46
 
  protected FSTEnum(FST<T> fst) {
47
 
    this.fst = fst;
48
 
    NO_OUTPUT = fst.outputs.getNoOutput();
49
 
    fst.getFirstArc(getArc(0));
50
 
    output[0] = NO_OUTPUT;
51
 
  }
52
 
 
53
 
  protected abstract int getTargetLabel();
54
 
  protected abstract int getCurrentLabel();
55
 
 
56
 
  protected abstract void setCurrentLabel(int label);
57
 
  protected abstract void grow();
58
 
 
59
 
  /** Rewinds enum state to match the shared prefix between
60
 
   *  current term and target term */
61
 
  protected final void rewindPrefix() throws IOException {
62
 
    if (upto == 0) {
63
 
      //System.out.println("  init");
64
 
      upto = 1;
65
 
      fst.readFirstTargetArc(getArc(0), getArc(1));
66
 
      return;
67
 
    }
68
 
    //System.out.println("  rewind upto=" + upto + " vs targetLength=" + targetLength);
69
 
 
70
 
    final int currentLimit = upto;
71
 
    upto = 1;
72
 
    while (upto < currentLimit && upto <= targetLength+1) {
73
 
      final int cmp = getCurrentLabel() - getTargetLabel();
74
 
      if (cmp < 0) {
75
 
        // seek forward
76
 
        break;
77
 
      } else if (cmp > 0) {
78
 
        // seek backwards -- reset this arc to the first arc
79
 
        final FST.Arc<T> arc = getArc(upto);
80
 
        fst.readFirstTargetArc(getArc(upto-1), arc);
81
 
        //System.out.println("    seek first arc");
82
 
        break;
83
 
      }
84
 
      upto++;
85
 
    }
86
 
  }
87
 
 
88
 
  protected void doNext() throws IOException {
89
 
    //System.out.println("FE: next upto=" + upto);
90
 
    if (upto == 0) {
91
 
      //System.out.println("  init");
92
 
      upto = 1;
93
 
      fst.readFirstTargetArc(getArc(0), getArc(1));
94
 
    } else {
95
 
      // pop
96
 
      //System.out.println("  check pop curArc target=" + arcs[upto].target + " label=" + arcs[upto].label + " isLast?=" + arcs[upto].isLast());
97
 
      while (arcs[upto].isLast()) {
98
 
        upto--;
99
 
        if (upto == 0) {
100
 
          //System.out.println("  eof");
101
 
          return;
102
 
        }
103
 
      }
104
 
      fst.readNextArc(arcs[upto]);
105
 
    }
106
 
 
107
 
    pushFirst();
108
 
  }
109
 
 
110
 
  // TODO: should we return a status here (SEEK_FOUND / SEEK_NOT_FOUND /
111
 
  // SEEK_END)?  saves the eq check above?
112
 
 
113
 
  /** Seeks to smallest term that's >= target. */
114
 
  protected void doSeekCeil() throws IOException {
115
 
 
116
 
    //System.out.println("    advance len=" + target.length + " curlen=" + current.length);
117
 
 
118
 
    // TODO: possibly caller could/should provide common
119
 
    // prefix length?  ie this work may be redundant if
120
 
    // caller is in fact intersecting against its own
121
 
    // automaton
122
 
 
123
 
    //System.out.println("FE.seekCeil upto=" + upto);
124
 
 
125
 
    // Save time by starting at the end of the shared prefix
126
 
    // b/w our current term & the target:
127
 
    rewindPrefix();
128
 
    //System.out.println("  after rewind upto=" + upto);
129
 
 
130
 
    FST.Arc<T> arc = getArc(upto);
131
 
    int targetLabel = getTargetLabel();
132
 
    //System.out.println("  init targetLabel=" + targetLabel);
133
 
 
134
 
    // Now scan forward, matching the new suffix of the target
135
 
    while(true) {
136
 
 
137
 
      //System.out.println("  cycle upto=" + upto + " arc.label=" + arc.label + " (" + (char) arc.label + ") vs targetLabel=" + targetLabel);
138
 
 
139
 
      if (arc.bytesPerArc != 0 && arc.label != -1) {
140
 
 
141
 
        // Arcs are fixed array -- use binary search to find
142
 
        // the target.
143
 
 
144
 
        final FST<T>.BytesReader in = fst.getBytesReader(0);
145
 
        int low = arc.arcIdx;
146
 
        int high = arc.numArcs-1;
147
 
        int mid = 0;
148
 
        //System.out.println("do arc array low=" + low + " high=" + high + " targetLabel=" + targetLabel);
149
 
        boolean found = false;
150
 
        while (low <= high) {
151
 
          mid = (low + high) >>> 1;
152
 
          in.pos = arc.posArcsStart - arc.bytesPerArc*mid - 1;
153
 
          final int midLabel = fst.readLabel(in);
154
 
          final int cmp = midLabel - targetLabel;
155
 
          //System.out.println("  cycle low=" + low + " high=" + high + " mid=" + mid + " midLabel=" + midLabel + " cmp=" + cmp);
156
 
          if (cmp < 0)
157
 
            low = mid + 1;
158
 
          else if (cmp > 0)
159
 
            high = mid - 1;
160
 
          else {
161
 
            found = true;
162
 
            break;
163
 
          }
164
 
        }
165
 
 
166
 
        // NOTE: this code is dup'd w/ the code below (in
167
 
        // the outer else clause):
168
 
        if (found) {
169
 
          // Match
170
 
          arc.arcIdx = mid-1;
171
 
          fst.readNextRealArc(arc, in);
172
 
          assert arc.arcIdx == mid;
173
 
          assert arc.label == targetLabel: "arc.label=" + arc.label + " vs targetLabel=" + targetLabel + " mid=" + mid;
174
 
          output[upto] = fst.outputs.add(output[upto-1], arc.output);
175
 
          if (targetLabel == FST.END_LABEL) {
176
 
            return;
177
 
          }
178
 
          setCurrentLabel(arc.label);
179
 
          incr();
180
 
          arc = fst.readFirstTargetArc(arc, getArc(upto));
181
 
          targetLabel = getTargetLabel();
182
 
          continue;
183
 
        } else if (low == arc.numArcs) {
184
 
          // Dead end
185
 
          arc.arcIdx = arc.numArcs-2;
186
 
          fst.readNextRealArc(arc, in);
187
 
          assert arc.isLast();
188
 
          // Dead end (target is after the last arc);
189
 
          // rollback to last fork then push
190
 
          upto--;
191
 
          while(true) {
192
 
            if (upto == 0) {
193
 
              return;
194
 
            }
195
 
            final FST.Arc<T> prevArc = getArc(upto);
196
 
            //System.out.println("  rollback upto=" + upto + " arc.label=" + prevArc.label + " isLast?=" + prevArc.isLast());
197
 
            if (!prevArc.isLast()) {
198
 
              fst.readNextArc(prevArc);
199
 
              pushFirst();
200
 
              return;
201
 
            }
202
 
            upto--;
203
 
          }
204
 
        } else {
205
 
          arc.arcIdx = (low > high ? low : high)-1;
206
 
          fst.readNextRealArc(arc, in);
207
 
          assert arc.label > targetLabel;
208
 
          pushFirst();
209
 
          return;
210
 
        }
211
 
      } else {
212
 
        // Arcs are not array'd -- must do linear scan:
213
 
        if (arc.label == targetLabel) {
214
 
          // recurse
215
 
          output[upto] = fst.outputs.add(output[upto-1], arc.output);
216
 
          if (targetLabel == FST.END_LABEL) {
217
 
            return;
218
 
          }
219
 
          setCurrentLabel(arc.label);
220
 
          incr();
221
 
          arc = fst.readFirstTargetArc(arc, getArc(upto));
222
 
          targetLabel = getTargetLabel();
223
 
        } else if (arc.label > targetLabel) {
224
 
          pushFirst();
225
 
          return;
226
 
        } else if (arc.isLast()) {
227
 
          // Dead end (target is after the last arc);
228
 
          // rollback to last fork then push
229
 
          upto--;
230
 
          while(true) {
231
 
            if (upto == 0) {
232
 
              return;
233
 
            }
234
 
            final FST.Arc<T> prevArc = getArc(upto);
235
 
            //System.out.println("  rollback upto=" + upto + " arc.label=" + prevArc.label + " isLast?=" + prevArc.isLast());
236
 
            if (!prevArc.isLast()) {
237
 
              fst.readNextArc(prevArc);
238
 
              pushFirst();
239
 
              return;
240
 
            }
241
 
            upto--;
242
 
          }
243
 
        } else {
244
 
          // keep scanning
245
 
          //System.out.println("    next scan");
246
 
          fst.readNextArc(arc);
247
 
        }
248
 
      }
249
 
    }
250
 
  }
251
 
 
252
 
  // TODO: should we return a status here (SEEK_FOUND / SEEK_NOT_FOUND /
253
 
  // SEEK_END)?  saves the eq check above?
254
 
  /** Seeks to largest term that's <= target. */
255
 
  protected void doSeekFloor() throws IOException {
256
 
 
257
 
    // TODO: possibly caller could/should provide common
258
 
    // prefix length?  ie this work may be redundant if
259
 
    // caller is in fact intersecting against its own
260
 
    // automaton
261
 
    //System.out.println("FE: seek floor upto=" + upto);
262
 
 
263
 
    // Save CPU by starting at the end of the shared prefix
264
 
    // b/w our current term & the target:
265
 
    rewindPrefix();
266
 
 
267
 
    //System.out.println("FE: after rewind upto=" + upto);
268
 
 
269
 
    FST.Arc<T> arc = getArc(upto);
270
 
    int targetLabel = getTargetLabel();
271
 
 
272
 
    //System.out.println("FE: init targetLabel=" + targetLabel);
273
 
 
274
 
    // Now scan forward, matching the new suffix of the target
275
 
    while(true) {
276
 
      //System.out.println("  cycle upto=" + upto + " arc.label=" + arc.label + " (" + (char) arc.label + ") targetLabel=" + targetLabel + " isLast?=" + arc.isLast());
277
 
 
278
 
      if (arc.bytesPerArc != 0 && arc.label != FST.END_LABEL) {
279
 
        // Arcs are fixed array -- use binary search to find
280
 
        // the target.
281
 
 
282
 
        final FST<T>.BytesReader in = fst.getBytesReader(0);
283
 
        int low = arc.arcIdx;
284
 
        int high = arc.numArcs-1;
285
 
        int mid = 0;
286
 
        //System.out.println("do arc array low=" + low + " high=" + high + " targetLabel=" + targetLabel);
287
 
        boolean found = false;
288
 
        while (low <= high) {
289
 
          mid = (low + high) >>> 1;
290
 
          in.pos = arc.posArcsStart - arc.bytesPerArc*mid - 1;
291
 
          final int midLabel = fst.readLabel(in);
292
 
          final int cmp = midLabel - targetLabel;
293
 
          //System.out.println("  cycle low=" + low + " high=" + high + " mid=" + mid + " midLabel=" + midLabel + " cmp=" + cmp);
294
 
          if (cmp < 0)
295
 
            low = mid + 1;
296
 
          else if (cmp > 0)
297
 
            high = mid - 1;
298
 
          else {
299
 
            found = true;
300
 
            break;
301
 
          }
302
 
        }
303
 
 
304
 
        // NOTE: this code is dup'd w/ the code below (in
305
 
        // the outer else clause):
306
 
        if (found) {
307
 
          // Match -- recurse
308
 
          //System.out.println("  match!  arcIdx=" + mid);
309
 
          arc.arcIdx = mid-1;
310
 
          fst.readNextRealArc(arc, in);
311
 
          assert arc.arcIdx == mid;
312
 
          assert arc.label == targetLabel: "arc.label=" + arc.label + " vs targetLabel=" + targetLabel + " mid=" + mid;
313
 
          output[upto] = fst.outputs.add(output[upto-1], arc.output);
314
 
          if (targetLabel == FST.END_LABEL) {
315
 
            return;
316
 
          }
317
 
          setCurrentLabel(arc.label);
318
 
          incr();
319
 
          arc = fst.readFirstTargetArc(arc, getArc(upto));
320
 
          targetLabel = getTargetLabel();
321
 
          continue;
322
 
        } else if (high == -1) {
323
 
          //System.out.println("  before first");
324
 
          // Very first arc is after our target
325
 
          // TODO: if each arc could somehow read the arc just
326
 
          // before, we can save this re-scan.  The ceil case
327
 
          // doesn't need this because it reads the next arc
328
 
          // instead:
329
 
          while(true) {
330
 
            // First, walk backwards until we find a first arc
331
 
            // that's before our target label:
332
 
            fst.readFirstTargetArc(getArc(upto-1), arc);
333
 
            if (arc.label < targetLabel) {
334
 
              // Then, scan forwards to the arc just before
335
 
              // the targetLabel:
336
 
              while(!arc.isLast() && fst.readNextArcLabel(arc) < targetLabel) {
337
 
                fst.readNextArc(arc);
338
 
              }
339
 
              pushLast();
340
 
              return;
341
 
            }
342
 
            upto--;
343
 
            if (upto == 0) {
344
 
              return;
345
 
            }
346
 
            targetLabel = getTargetLabel();
347
 
            arc = getArc(upto);
348
 
          }
349
 
        } else {
350
 
          // There is a floor arc:
351
 
          arc.arcIdx = (low > high ? high : low)-1;
352
 
          //System.out.println(" hasFloor arcIdx=" + (arc.arcIdx+1));
353
 
          fst.readNextRealArc(arc, in);
354
 
          assert arc.isLast() || fst.readNextArcLabel(arc) > targetLabel;
355
 
          assert arc.label < targetLabel;
356
 
          pushLast();
357
 
          return;
358
 
        }        
359
 
      } else {
360
 
 
361
 
        if (arc.label == targetLabel) {
362
 
          // Match -- recurse
363
 
          output[upto] = fst.outputs.add(output[upto-1], arc.output);
364
 
          if (targetLabel == FST.END_LABEL) {
365
 
            return;
366
 
          }
367
 
          setCurrentLabel(arc.label);
368
 
          incr();
369
 
          arc = fst.readFirstTargetArc(arc, getArc(upto));
370
 
          targetLabel = getTargetLabel();
371
 
        } else if (arc.label > targetLabel) {
372
 
          // TODO: if each arc could somehow read the arc just
373
 
          // before, we can save this re-scan.  The ceil case
374
 
          // doesn't need this because it reads the next arc
375
 
          // instead:
376
 
          while(true) {
377
 
            // First, walk backwards until we find a first arc
378
 
            // that's before our target label:
379
 
            fst.readFirstTargetArc(getArc(upto-1), arc);
380
 
            if (arc.label < targetLabel) {
381
 
              // Then, scan forwards to the arc just before
382
 
              // the targetLabel:
383
 
              while(!arc.isLast() && fst.readNextArcLabel(arc) < targetLabel) {
384
 
                fst.readNextArc(arc);
385
 
              }
386
 
              pushLast();
387
 
              return;
388
 
            }
389
 
            upto--;
390
 
            if (upto == 0) {
391
 
              return;
392
 
            }
393
 
            targetLabel = getTargetLabel();
394
 
            arc = getArc(upto);
395
 
          }
396
 
        } else if (!arc.isLast()) {
397
 
          //System.out.println("  check next label=" + fst.readNextArcLabel(arc) + " (" + (char) fst.readNextArcLabel(arc) + ")");
398
 
          if (fst.readNextArcLabel(arc) > targetLabel) {
399
 
            pushLast();
400
 
            return;
401
 
          } else {
402
 
            // keep scanning
403
 
            fst.readNextArc(arc);
404
 
          }
405
 
        } else {
406
 
          pushLast();
407
 
          return;
408
 
        }
409
 
      }
410
 
    }
411
 
  }
412
 
 
413
 
  private void incr() {
414
 
    upto++;
415
 
    grow();
416
 
    if (arcs.length <= upto) {
417
 
      @SuppressWarnings("unchecked") final FST.Arc<T>[] newArcs =
418
 
        new FST.Arc[ArrayUtil.oversize(1+upto, RamUsageEstimator.NUM_BYTES_OBJECT_REF)];
419
 
      System.arraycopy(arcs, 0, newArcs, 0, arcs.length);
420
 
      arcs = newArcs;
421
 
    }
422
 
    if (output.length <= upto) {
423
 
      @SuppressWarnings("unchecked") final T[] newOutput =
424
 
        (T[]) new Object[ArrayUtil.oversize(1+upto, RamUsageEstimator.NUM_BYTES_OBJECT_REF)];
425
 
      System.arraycopy(output, 0, newOutput, 0, output.length);
426
 
      output = newOutput;
427
 
    }
428
 
  }
429
 
 
430
 
  // Appends current arc, and then recurses from its target,
431
 
  // appending first arc all the way to the final node
432
 
  private void pushFirst() throws IOException {
433
 
 
434
 
    FST.Arc<T> arc = arcs[upto];
435
 
    assert arc != null;
436
 
 
437
 
    while (true) {
438
 
      output[upto] = fst.outputs.add(output[upto-1], arc.output);
439
 
      if (arc.label == FST.END_LABEL) {
440
 
        // Final node
441
 
        break;
442
 
      }
443
 
      //System.out.println("  pushFirst label=" + (char) arc.label + " upto=" + upto + " output=" + fst.outputs.outputToString(output[upto]));
444
 
      setCurrentLabel(arc.label);
445
 
      incr();
446
 
      
447
 
      final FST.Arc<T> nextArc = getArc(upto);
448
 
      fst.readFirstTargetArc(arc, nextArc);
449
 
      arc = nextArc;
450
 
    }
451
 
  }
452
 
 
453
 
  // Recurses from current arc, appending last arc all the
454
 
  // way to the first final node
455
 
  private void pushLast() throws IOException {
456
 
 
457
 
    FST.Arc<T> arc = arcs[upto];
458
 
    assert arc != null;
459
 
 
460
 
    while (true) {
461
 
      setCurrentLabel(arc.label);
462
 
      output[upto] = fst.outputs.add(output[upto-1], arc.output);
463
 
      if (arc.label == FST.END_LABEL) {
464
 
        // Final node
465
 
        break;
466
 
      }
467
 
      incr();
468
 
 
469
 
      arc = fst.readLastTargetArc(arc, getArc(upto));
470
 
    }
471
 
  }
472
 
 
473
 
  private FST.Arc<T> getArc(int idx) {
474
 
    if (arcs[idx] == null) {
475
 
      arcs[idx] = new FST.Arc<T>();
476
 
    }
477
 
    return arcs[idx];
478
 
  }
479
 
}