FieldCacheImpl.java
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 (instanceof Entry) {
070         Entry other = (Entryo;
071         if (other.reader == reader && other.field == field && other.type == type) {
072           if (other.custom == null) {
073             if (custom == nullreturn 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() != fieldbreak;
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() != fieldbreak;
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() != fieldbreak;
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() != fieldbreak;
252 
253             // store term text
254             // we expect that there is at most one term per document
255             if (t >= mterms.lengththrow 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 (StringIndexret;
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() != fieldbreak;
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 }