Clover coverage report -
Coverage timestamp: Fri Nov 19 2004 13:41:51 PST
file stats: LOC: 282   Methods: 17
NCLOC: 223   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
Searcher.java 79.6% 91.5% 94.1% 88.6%
coverage coverage
 1    package photospace.search;
 2   
 3    import java.io.*;
 4    import java.util.*;
 5    import org.apache.commons.logging.*;
 6    import org.apache.lucene.document.*;
 7    import org.apache.lucene.index.*;
 8    import org.apache.lucene.queryParser.*;
 9    import org.apache.lucene.search.*;
 10    import photospace.meta.*;
 11   
 12    public class Searcher
 13    {
 14    private static final Log log = LogFactory.getLog(Searcher.class);
 15   
 16    public static final int ASCENDING = 1;
 17    public static final int DESCENDING = -1;
 18   
 19    // String searching is slower but INT is not an option b/c date.getTime() is a long and too big :(
 20    public static final Sort CREATED_ASCENDING = new Sort(new SortField(DocumentFactory.SORT_FIELD, SortField.STRING));
 21    public static final Sort CREATED_DESCENDING = new Sort(new SortField(DocumentFactory.SORT_FIELD, SortField.STRING, true));
 22   
 23    public static final Query PHOTO_CONSTRAINT = new TermQuery(new Term(DocumentFactory.TYPE_FIELD, DocumentFactory.PHOTO_TYPE));
 24   
 25    private SearchIndex index;
 26    private DocumentFactory factory = new DocumentFactory();
 27   
 28  9 public Meta browse(String path, int sort, int start, int end) throws IOException
 29    {
 30  9 return browse(path, null, sort, start, end);
 31    }
 32   
 33  10 public Meta browse(String path, Query constraint, int sort, int start, int end) throws IOException
 34    {
 35  10 Document doc = findDocument(path);
 36  1 if (doc == null) return null;
 37   
 38  9 Meta meta = factory.createMeta(doc);
 39  9 assignParents(meta);
 40   
 41  1 if (!(meta instanceof CollectionMeta)) return meta;
 42   
 43  8 CollectionMeta collection = (CollectionMeta) meta;
 44   
 45  8 Sort order = (sort == ASCENDING) ? CREATED_ASCENDING : CREATED_DESCENDING;
 46   
 47  8 Query query = new TermQuery(new Term(DocumentFactory.PARENT_FIELD, collection.getPath()));
 48  8 if (constraint != null)
 49    {
 50  1 BooleanQuery constrained = new BooleanQuery();
 51  1 constrained.add(query, true, false);
 52  1 constrained.add(constraint, true, false);
 53  1 query = constrained;
 54    }
 55   
 56  8 SearchResult children = search(query, null, order, start, end);
 57  8 collection.addFiles(children.getFiles());
 58  8 collection.setStart(children.getStart());
 59  8 collection.setEnd(children.getEnd());
 60  8 collection.setTotal(children.getTotal());
 61   
 62  8 return collection;
 63    }
 64   
 65  9 private void assignParents(Meta meta) throws IOException
 66    {
 67  5 if (meta.getParentPath() == null) return;
 68  4 CollectionMeta parent = (CollectionMeta) browse(meta.getParentPath(), DESCENDING, -1, -1);
 69  4 meta.setParent(parent);
 70    }
 71   
 72    /**
 73    * Retrieves the set of field names from the index
 74    */
 75  0 public Collection getFieldNames() throws IOException
 76    {
 77  0 IndexReader reader = index.getReader();
 78  0 List names = new ArrayList(reader.getFieldNames(true));
 79  0 Collections.sort(names);
 80  0 return names;
 81    }
 82   
 83    /**
 84    * Retrieves a collection of Matches for a specific Meta path
 85    */
 86  1 public Collection getDocumentMatches(String path) throws IOException
 87    {
 88  1 Collection matches = new ArrayList();
 89   
 90  1 Document doc = findDocument(path);
 91  0 if (doc == null) return matches;
 92   
 93  1 for (Enumeration fields = doc.fields(); fields.hasMoreElements(); )
 94    {
 95  9 Field field = (Field) fields.nextElement();
 96  9 matches.addAll(getFieldMatches(field.name(), field.stringValue()));
 97    }
 98   
 99  1 return matches;
 100    }
 101   
 102    /**
 103    * Retrieves a collection of Matches for a specific Meta path and field
 104    */
 105  3 public Collection getDocumentMatches(String path, String field) throws IOException
 106    {
 107  3 Collection matches = new ArrayList();
 108   
 109  3 Document doc = findDocument(path);
 110  0 if (doc == null) return matches;
 111   
 112  3 String[] values = doc.getValues(field);
 113  0 if (values == null || values.length == 0 || "".equals(values[0])) return matches;
 114   
 115  3 for (int i = 0; i < values.length; i++)
 116    {
 117  4 matches.addAll(getFieldMatches(field, values[i]));
 118    }
 119   
 120  3 return matches;
 121    }
 122   
 123  14 private Document findDocument(String path) throws IOException
 124    {
 125  14 IndexReader reader = index.getReader();
 126  14 TermDocs docs = reader.termDocs(new Term("path", path));
 127  14 if (! docs.next())
 128    {
 129  1 log.warn("No document found for path " + path);
 130  1 return null;
 131    }
 132  13 return reader.document(docs.doc());
 133    }
 134   
 135  2 public Collection getFieldMatches(String field) throws IOException
 136    {
 137  2 return getFieldMatches(field, "");
 138    }
 139   
 140  15 private Collection getFieldMatches(String field, String value)
 141    throws IOException
 142    {
 143  15 IndexReader reader = index.getReader();
 144  15 Collection values = new ArrayList();
 145  15 TermEnum terms = reader.terms(new Term(field, value));
 146  15 while (field.equals(terms.term().field()) && ("".equals(value) || value.equals(terms.term().text())))
 147    {
 148  17 if (!"".equals(terms.term().text())) values.add(new Match(terms.term(), terms.docFreq()));
 149  1 if (!terms.next()) break;
 150    }
 151  15 return values;
 152    }
 153   
 154  5 public SearchResult search(String query, int sort, int start, int end) throws ParseException, IOException
 155    {
 156  5 return search(query, null, sort, start, end);
 157    }
 158   
 159  6 public SearchResult search(String query, Query constraint, int sort, int start, int end) throws ParseException, IOException
 160    {
 161  6 ParseResult search = parseQuery(query);
 162  6 if (search.filter != null && empty(search.query))
 163    {
 164  1 search.query = new TermQuery(new Term(DocumentFactory.ALL_FIELD, DocumentFactory.ALL_VALUE));
 165    }
 166  6 if (constraint != null)
 167    {
 168  1 BooleanQuery constrained = new BooleanQuery();
 169  1 constrained.add(search.query, true, false);
 170  1 constrained.add(constraint, true, false);
 171  1 search.query = constrained;
 172    }
 173  6 Sort order = (sort == ASCENDING) ? CREATED_ASCENDING : CREATED_DESCENDING;
 174  6 SearchResult result = search(search.query, search.filter, order, start, end);
 175  6 result.setQuery(query);
 176  6 result.setName(query);
 177  6 result.setTitle("[" + query + "]");
 178  6 result.setDescription("Search results for: " + query);
 179  6 return result;
 180    }
 181   
 182  6 private ParseResult parseQuery(String queryString) throws ParseException
 183    {
 184  6 MetaAnalyzer analyzer = new MetaAnalyzer();
 185  6 Query query = QueryParser.parse(queryString, DocumentFactory.TEXT_FIELD, analyzer);
 186  6 ParseResult result = new ParseResult();
 187  6 result.query = query;
 188  6 if (analyzer.hasPoint())
 189    {
 190  1 result.filter = new LocationFilter(analyzer.getLatitude(), analyzer.getLongitude(), analyzer.getRadius());
 191    }
 192  6 return result;
 193    }
 194   
 195  2 protected SearchResult search(Query query)
 196    throws IOException
 197    {
 198  2 return search(query, null, Searcher.CREATED_DESCENDING);
 199    }
 200   
 201  1 private boolean empty(Query query)
 202    {
 203  1 return query instanceof BooleanQuery && ((BooleanQuery) query).getClauses().length == 0;
 204    }
 205   
 206  5 protected SearchResult search(Query query, Filter filter, Sort sort)
 207    throws IOException
 208    {
 209  5 return search(query, filter, sort, 0, -1);
 210    }
 211   
 212  24 protected SearchResult search(Query query, Filter filter, Sort sort, int start, int end)
 213    throws IOException
 214    {
 215  0 if (start < -1) throw new IllegalArgumentException("Start value of " + start + " must be -1 or greater");
 216  0 if (end < -1) throw new IllegalArgumentException("End value of " + end + " must be be -1 or greater");
 217   
 218  24 log.debug("query=" + query + ", filter=" + filter + ", sort=" + sort);
 219   
 220  24 SearchResult result = new SearchResult();
 221  24 result.setQuery(query.toString());
 222  24 result.setName(query.toString());
 223  24 result.setTitle("[" + query.toString() + "]");
 224  24 result.setDescription("Search results for: " + query.toString());
 225  24 result.setCreated(new Date());
 226   
 227  24 IndexReader reader = index.getReader();
 228  24 IndexSearcher searcher = new IndexSearcher(reader);
 229   
 230  24 Hits hits = searcher.search(query, filter, sort);
 231   
 232  24 result.setStart(start);
 233  24 result.setEnd(end < start && start < 0 ? start : (end >= hits.length() || end < start ? hits.length() - 1 : end));
 234  24 result.setTotal(hits.length());
 235   
 236  7 if (end <= start && start < 0) return result;
 237   
 238  17 float threshold = 0.0f; // todo: determine a good threshold
 239   
 240  17 for (int i = result.getStart() < 0 ? 0 : result.getStart(); i <= result.getEnd(); i++)
 241    {
 242  0 if (hits.score(i) < threshold) break;
 243  42 Meta meta = factory.createMeta(hits.doc(i));
 244  42 try
 245    {
 246  42 if (meta instanceof CollectionMeta)
 247    {
 248  3 BooleanQuery b = new BooleanQuery();
 249  3 b.add(new BooleanClause(new TermQuery(new Term(DocumentFactory.PARENT_FIELD, meta.getPath())), true, false));
 250  3 b.add(new BooleanClause(PHOTO_CONSTRAINT, true, false));
 251   
 252  3 SearchResult children = search(b, null, CREATED_ASCENDING, 0, 3);
 253  3 CollectionMeta collection = (CollectionMeta) meta;
 254  3 collection.setTotal(children.getTotal());
 255  3 collection.setStart(children.getStart());
 256  3 collection.setEnd(children.getEnd());
 257  3 collection.addFiles(children.getFiles());
 258    }
 259    }
 260    catch (Exception e)
 261    {
 262  0 throw new RuntimeException(e);
 263    }
 264  42 result.addFile(meta);
 265    }
 266   
 267  17 result.setDuration(new Date().getTime() - result.getCreated().getTime());
 268   
 269  17 return result;
 270    }
 271   
 272  11 public void setIndex(SearchIndex index)
 273    {
 274  11 this.index = index;
 275    }
 276   
 277    private static class ParseResult
 278    {
 279    Query query;
 280    Filter filter;
 281    }
 282    }