1 package org.apache.lucene.search.spans; 2 3 18 19 import java.io.IOException ; 20 21 import java.util.List ; 22 import java.util.ArrayList ; 23 24 import org.apache.lucene.index.IndexReader; 25 import org.apache.lucene.util.PriorityQueue; 26 27 class NearSpans implements Spans { 28 private SpanNearQuery query; 29 30 private List ordered = new ArrayList (); private int slop; private boolean inOrder; 34 private SpansCell first; private SpansCell last; 37 private int totalLength; 39 private CellQueue queue; private SpansCell max; 42 private boolean more = true; private boolean firstTime = true; 45 private class CellQueue extends PriorityQueue { 46 public CellQueue(int size) { 47 initialize(size); 48 } 49 50 protected final boolean lessThan(Object o1, Object o2) { 51 SpansCell spans1 = (SpansCell)o1; 52 SpansCell spans2 = (SpansCell)o2; 53 if (spans1.doc() == spans2.doc()) { 54 if (spans1.start() == spans2.start()) { 55 if (spans1.end() == spans2.end()) { 56 return spans1.index > spans2.index; 57 } else { 58 return spans1.end() < spans2.end(); 59 } 60 } else { 61 return spans1.start() < spans2.start(); 62 } 63 } else { 64 return spans1.doc() < spans2.doc(); 65 } 66 } 67 } 68 69 70 71 private class SpansCell implements Spans { 72 private Spans spans; 73 private SpansCell next; 74 private int length = -1; 75 private int index; 76 77 public SpansCell(Spans spans, int index) { 78 this.spans = spans; 79 this.index = index; 80 } 81 82 public boolean next() throws IOException { 83 if (length != -1) totalLength -= length; 85 86 boolean more = spans.next(); 88 if (more) { 89 length = end() - start(); totalLength += length; 92 if (max == null || doc() > max.doc() || (doc() == max.doc() && end() > max.end())) 94 max = this; 95 } 96 97 return more; 98 } 99 100 public boolean skipTo(int target) throws IOException { 101 if (length != -1) totalLength -= length; 103 104 boolean more = spans.skipTo(target); 106 if (more) { 107 length = end() - start(); totalLength += length; 110 if (max == null || doc() > max.doc() || (doc() == max.doc() && end() > max.end())) 112 max = this; 113 } 114 115 return more; 116 } 117 118 public int doc() { return spans.doc(); } 119 public int start() { return spans.start(); } 120 public int end() { return spans.end(); } 121 122 public String toString() { return spans.toString() + "#" + index; } 123 } 124 125 public NearSpans(SpanNearQuery query, IndexReader reader) 126 throws IOException { 127 this.query = query; 128 this.slop = query.getSlop(); 129 this.inOrder = query.isInOrder(); 130 131 SpanQuery[] clauses = query.getClauses(); queue = new CellQueue(clauses.length); 133 for (int i = 0; i < clauses.length; i++) { 134 SpansCell cell = new SpansCell(clauses[i].getSpans(reader), i); 136 ordered.add(cell); } 138 } 139 140 public boolean next() throws IOException { 141 if (firstTime) { 142 initList(true); 143 listToQueue(); firstTime = false; 145 } else if (more) { 146 more = min().next(); if (more) 148 queue.adjustTop(); } 150 151 while (more) { 152 153 boolean queueStale = false; 154 155 if (min().doc() != max.doc()) { queueToList(); 157 queueStale = true; 158 } 159 160 162 while (more && first.doc() < last.doc()) { 163 more = first.skipTo(last.doc()); firstToLast(); queueStale = true; 166 } 167 168 if (!more) return false; 169 170 172 if (queueStale) { listToQueue(); 174 queueStale = false; 175 } 176 177 if (atMatch()) 178 return true; 179 180 if (inOrder && checkSlop()) { 182 183 more = firstNonOrderedNextToPartialList(); 184 if (more) { 185 partialListToQueue(); 186 } 187 } else { 188 more = min().next(); 189 if (more) { 190 queue.adjustTop(); } 192 } 193 } 194 return false; } 196 197 public boolean skipTo(int target) throws IOException { 198 if (firstTime) { initList(false); 200 for (SpansCell cell = first; more && cell!=null; cell=cell.next) { 201 more = cell.skipTo(target); } 203 if (more) { 204 listToQueue(); 205 } 206 firstTime = false; 207 } else { while (more && min().doc() < target) { more = min().skipTo(target); 210 if (more) 211 queue.adjustTop(); 212 } 213 } 214 if (more) { 215 216 if (atMatch()) return true; 218 219 return next(); } 221 222 return false; 223 } 224 225 private SpansCell min() { return (SpansCell)queue.top(); } 226 227 public int doc() { return min().doc(); } 228 public int start() { return min().start(); } 229 public int end() { return max.end(); } 230 231 232 public String toString() { 233 return "spans("+query.toString()+")@"+ 234 (firstTime?"START":(more?(doc()+":"+start()+"-"+end()):"END")); 235 } 236 237 private void initList(boolean next) throws IOException { 238 for (int i = 0; more && i < ordered.size(); i++) { 239 SpansCell cell = (SpansCell)ordered.get(i); 240 if (next) 241 more = cell.next(); if (more) { 243 addToList(cell); } 245 } 246 } 247 248 private void addToList(SpansCell cell) { 249 if (last != null) { last.next = cell; 251 } else 252 first = cell; 253 last = cell; 254 cell.next = null; 255 } 256 257 private void firstToLast() { 258 last.next = first; last = first; 260 first = first.next; 261 last.next = null; 262 } 263 264 private void queueToList() { 265 last = first = null; 266 while (queue.top() != null) { 267 addToList((SpansCell)queue.pop()); 268 } 269 } 270 271 private boolean firstNonOrderedNextToPartialList() throws IOException { 272 275 last = first = null; 276 int orderedIndex = 0; 277 while (queue.top() != null) { 278 SpansCell cell = (SpansCell)queue.pop(); 279 addToList(cell); 280 if (cell.index == orderedIndex) { 281 orderedIndex++; 282 } else { 283 return cell.next(); 284 } 290 } 291 throw new RuntimeException ("Unexpected: ordered"); 292 } 293 294 private void listToQueue() { 295 queue.clear(); partialListToQueue(); 297 } 298 299 private void partialListToQueue() { 300 for (SpansCell cell = first; cell != null; cell = cell.next) { 301 queue.put(cell); } 303 } 304 305 private boolean atMatch() { 306 return (min().doc() == max.doc()) 307 && checkSlop() 308 && (!inOrder || matchIsOrdered()); 309 } 310 311 private boolean checkSlop() { 312 int matchLength = max.end() - min().start(); 313 return (matchLength - totalLength) <= slop; 314 } 315 316 private boolean matchIsOrdered() { 317 int lastStart = -1; 318 for (int i = 0; i < ordered.size(); i++) { 319 int start = ((SpansCell)ordered.get(i)).start(); 320 if (!(start > lastStart)) 321 return false; 322 lastStart = start; 323 } 324 return true; 325 } 326 } 327 | Popular Tags |