001 package gate.creole.annic.apache.lucene.search;
002
003 /**
004 * Copyright 2004 The Apache Software Foundation
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 import gate.creole.annic.apache.lucene.index.IndexReader;
020 import gate.creole.annic.apache.lucene.index.Term;
021 import gate.creole.annic.apache.lucene.index.TermDocs;
022 import gate.creole.annic.apache.lucene.index.TermEnum;
023
024 import java.io.IOException;
025 import java.util.Map;
026 import java.util.WeakHashMap;
027
028 /**
029 * Expert: The default cache implementation, storing all values in memory.
030 * A WeakHashMap is used for storage.
031 *
032 * <p>Created: May 19, 2004 4:40:36 PM
033 *
034 * @author Tim Jones (Nacimiento Software)
035 * @since lucene 1.4
036 * @version $Id: FieldCacheImpl.java 529 2004-10-05 11:55:26Z niraj $
037 */
038 class FieldCacheImpl
039 implements FieldCache {
040
041 /** Expert: Every key in the internal cache is of this type. */
042 static class Entry {
043 final IndexReader reader; // which Reader
044 final String field; // which Field
045 final int type; // which SortField type
046 final Object custom; // which custom comparator
047 final int hashcode; // unique for this object
048
049 /** Creates one of these objects. */
050 Entry (IndexReader reader, String field, int type) {
051 this.reader = reader;
052 this.field = field.intern();
053 this.type = type;
054 this.custom = null;
055 this.hashcode = reader.hashCode() ^ field.hashCode() ^ type;
056 }
057
058 /** Creates one of these objects for a custom comparator. */
059 Entry (IndexReader reader, String field, Object custom) {
060 this.reader = reader;
061 this.field = field.intern();
062 this.type = SortField.CUSTOM;
063 this.custom = custom;
064 this.hashcode = reader.hashCode() ^ field.hashCode() ^ type ^ custom.hashCode();
065 }
066
067 /** Two of these are equal iff they reference the same reader, field and type. */
068 public boolean equals (Object o) {
069 if (o instanceof Entry) {
070 Entry other = (Entry) o;
071 if (other.reader == reader && other.field == field && other.type == type) {
072 if (other.custom == null) {
073 if (custom == null) return true;
074 } else if (other.custom.equals (custom)) {
075 return true;
076 }
077 }
078 }
079 return false;
080 }
081
082 /** Composes a hashcode based on the referenced reader, field and type. */
083 public int hashCode() {
084 return hashcode;
085 }
086 }
087
088
089 /** The internal cache. Maps Entry to array of interpreted term values. **/
090 final Map cache = new WeakHashMap();
091
092 /** See if an object is in the cache. */
093 Object lookup (IndexReader reader, String field, int type) {
094 Entry entry = new Entry (reader, field, type);
095 synchronized (this) {
096 return cache.get (entry);
097 }
098 }
099
100 /** See if a custom object is in the cache. */
101 Object lookup (IndexReader reader, String field, Object comparer) {
102 Entry entry = new Entry (reader, field, comparer);
103 synchronized (this) {
104 return cache.get (entry);
105 }
106 }
107
108 /** Put an object into the cache. */
109 Object store (IndexReader reader, String field, int type, Object value) {
110 Entry entry = new Entry (reader, field, type);
111 synchronized (this) {
112 return cache.put (entry, value);
113 }
114 }
115
116 /** Put a custom object into the cache. */
117 Object store (IndexReader reader, String field, Object comparer, Object value) {
118 Entry entry = new Entry (reader, field, comparer);
119 synchronized (this) {
120 return cache.put (entry, value);
121 }
122 }
123
124 // inherit javadocs
125 public int[] getInts (IndexReader reader, String field)
126 throws IOException {
127 field = field.intern();
128 Object ret = lookup (reader, field, SortField.INT);
129 if (ret == null) {
130 final int[] retArray = new int[reader.maxDoc()];
131 if (retArray.length > 0) {
132 TermDocs termDocs = reader.termDocs();
133 TermEnum termEnum = reader.terms (new Term (field, ""));
134 try {
135 if (termEnum.term() == null) {
136 throw new RuntimeException ("no terms in field " + field);
137 }
138 do {
139 Term term = termEnum.term();
140 if (term.field() != field) break;
141 int termval = Integer.parseInt (term.text());
142 termDocs.seek (termEnum);
143 while (termDocs.next()) {
144 retArray[termDocs.doc()] = termval;
145 }
146 } while (termEnum.next());
147 } finally {
148 termDocs.close();
149 termEnum.close();
150 }
151 }
152 store (reader, field, SortField.INT, retArray);
153 return retArray;
154 }
155 return (int[]) ret;
156 }
157
158 // inherit javadocs
159 public float[] getFloats (IndexReader reader, String field)
160 throws IOException {
161 field = field.intern();
162 Object ret = lookup (reader, field, SortField.FLOAT);
163 if (ret == null) {
164 final float[] retArray = new float[reader.maxDoc()];
165 if (retArray.length > 0) {
166 TermDocs termDocs = reader.termDocs();
167 TermEnum termEnum = reader.terms (new Term (field, ""));
168 try {
169 if (termEnum.term() == null) {
170 throw new RuntimeException ("no terms in field " + field);
171 }
172 do {
173 Term term = termEnum.term();
174 if (term.field() != field) break;
175 float termval = Float.parseFloat (term.text());
176 termDocs.seek (termEnum);
177 while (termDocs.next()) {
178 retArray[termDocs.doc()] = termval;
179 }
180 } while (termEnum.next());
181 } finally {
182 termDocs.close();
183 termEnum.close();
184 }
185 }
186 store (reader, field, SortField.FLOAT, retArray);
187 return retArray;
188 }
189 return (float[]) ret;
190 }
191
192 // inherit javadocs
193 public String[] getStrings (IndexReader reader, String field)
194 throws IOException {
195 field = field.intern();
196 Object ret = lookup (reader, field, SortField.STRING);
197 if (ret == null) {
198 final String[] retArray = new String[reader.maxDoc()];
199 if (retArray.length > 0) {
200 TermDocs termDocs = reader.termDocs();
201 TermEnum termEnum = reader.terms (new Term (field, ""));
202 try {
203 if (termEnum.term() == null) {
204 throw new RuntimeException ("no terms in field " + field);
205 }
206 do {
207 Term term = termEnum.term();
208 if (term.field() != field) break;
209 String termval = term.text();
210 termDocs.seek (termEnum);
211 while (termDocs.next()) {
212 retArray[termDocs.doc()] = termval;
213 }
214 } while (termEnum.next());
215 } finally {
216 termDocs.close();
217 termEnum.close();
218 }
219 }
220 store (reader, field, SortField.STRING, retArray);
221 return retArray;
222 }
223 return (String[]) ret;
224 }
225
226 // inherit javadocs
227 public StringIndex getStringIndex (IndexReader reader, String field)
228 throws IOException {
229 field = field.intern();
230 Object ret = lookup (reader, field, STRING_INDEX);
231 if (ret == null) {
232 final int[] retArray = new int[reader.maxDoc()];
233 String[] mterms = new String[reader.maxDoc()+1];
234 if (retArray.length > 0) {
235 TermDocs termDocs = reader.termDocs();
236 TermEnum termEnum = reader.terms (new Term (field, ""));
237 int t = 0; // current term number
238
239 // an entry for documents that have no terms in this field
240 // should a document with no terms be at top or bottom?
241 // this puts them at the top - if it is changed, FieldDocSortedHitQueue
242 // needs to change as well.
243 mterms[t++] = null;
244
245 try {
246 if (termEnum.term() == null) {
247 throw new RuntimeException ("no terms in field " + field);
248 }
249 do {
250 Term term = termEnum.term();
251 if (term.field() != field) break;
252
253 // store term text
254 // we expect that there is at most one term per document
255 if (t >= mterms.length) throw new RuntimeException ("there are more terms than documents in field \"" + field + "\"");
256 mterms[t] = term.text();
257
258 termDocs.seek (termEnum);
259 while (termDocs.next()) {
260 retArray[termDocs.doc()] = t;
261 }
262
263 t++;
264 } while (termEnum.next());
265 } finally {
266 termDocs.close();
267 termEnum.close();
268 }
269
270 if (t == 0) {
271 // if there are no terms, make the term array
272 // have a single null entry
273 mterms = new String[1];
274 } else if (t < mterms.length) {
275 // if there are less terms than documents,
276 // trim off the dead array space
277 String[] terms = new String[t];
278 System.arraycopy (mterms, 0, terms, 0, t);
279 mterms = terms;
280 }
281 }
282 StringIndex value = new StringIndex (retArray, mterms);
283 store (reader, field, STRING_INDEX, value);
284 return value;
285 }
286 return (StringIndex) ret;
287 }
288
289 /** The pattern used to detect integer values in a field */
290 /** removed for java 1.3 compatibility
291 protected static final Pattern pIntegers = Pattern.compile ("[0-9\\-]+");
292 **/
293
294 /** The pattern used to detect float values in a field */
295 /**
296 * removed for java 1.3 compatibility
297 * protected static final Object pFloats = Pattern.compile ("[0-9+\\-\\.eEfFdD]+");
298 */
299
300 // inherit javadocs
301 public Object getAuto (IndexReader reader, String field)
302 throws IOException {
303 field = field.intern();
304 Object ret = lookup (reader, field, SortField.AUTO);
305 if (ret == null) {
306 TermEnum enumerator = reader.terms (new Term (field, ""));
307 try {
308 Term term = enumerator.term();
309 if (term == null) {
310 throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
311 }
312 if (term.field() == field) {
313 String termtext = term.text().trim();
314
315 /**
316 * Java 1.4 level code:
317
318 if (pIntegers.matcher(termtext).matches())
319 return IntegerSortedHitQueue.comparator (reader, enumerator, field);
320
321 else if (pFloats.matcher(termtext).matches())
322 return FloatSortedHitQueue.comparator (reader, enumerator, field);
323 */
324
325 // Java 1.3 level code:
326 try {
327 Integer.parseInt (termtext);
328 ret = getInts (reader, field);
329 } catch (NumberFormatException nfe1) {
330 try {
331 Float.parseFloat (termtext);
332 ret = getFloats (reader, field);
333 } catch (NumberFormatException nfe2) {
334 ret = getStringIndex (reader, field);
335 }
336 }
337 if (ret != null) {
338 store (reader, field, SortField.AUTO, ret);
339 }
340 } else {
341 throw new RuntimeException ("field \"" + field + "\" does not appear to be indexed");
342 }
343 } finally {
344 enumerator.close();
345 }
346
347 }
348 return ret;
349 }
350
351 // inherit javadocs
352 public Comparable[] getCustom (IndexReader reader, String field, SortComparator comparator)
353 throws IOException {
354 field = field.intern();
355 Object ret = lookup (reader, field, comparator);
356 if (ret == null) {
357 final Comparable[] retArray = new Comparable[reader.maxDoc()];
358 if (retArray.length > 0) {
359 TermDocs termDocs = reader.termDocs();
360 TermEnum termEnum = reader.terms (new Term (field, ""));
361 try {
362 if (termEnum.term() == null) {
363 throw new RuntimeException ("no terms in field " + field);
364 }
365 do {
366 Term term = termEnum.term();
367 if (term.field() != field) break;
368 Comparable termval = comparator.getComparable (term.text());
369 termDocs.seek (termEnum);
370 while (termDocs.next()) {
371 retArray[termDocs.doc()] = termval;
372 }
373 } while (termEnum.next());
374 } finally {
375 termDocs.close();
376 termEnum.close();
377 }
378 }
379 store (reader, field, SortField.CUSTOM, retArray);
380 return retArray;
381 }
382 return (String[]) ret;
383 }
384
385 }
|