1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.search.lucene;
16  
17  import com.liferay.portal.kernel.dao.orm.QueryUtil;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.search.Document;
21  import com.liferay.portal.kernel.search.DocumentImpl;
22  import com.liferay.portal.kernel.search.Field;
23  import com.liferay.portal.kernel.search.Hits;
24  import com.liferay.portal.kernel.search.HitsImpl;
25  import com.liferay.portal.kernel.search.IndexSearcher;
26  import com.liferay.portal.kernel.search.Query;
27  import com.liferay.portal.kernel.search.SearchException;
28  import com.liferay.portal.kernel.search.Sort;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Time;
31  import com.liferay.portal.kernel.util.Validator;
32  
33  import java.io.IOException;
34  
35  import java.util.List;
36  
37  import org.apache.lucene.queryParser.ParseException;
38  import org.apache.lucene.search.BooleanQuery;
39  import org.apache.lucene.search.SortField;
40  
41  /**
42   * <a href="LuceneIndexSearcherImpl.java.html"><b><i>View Source</i></b></a>
43   *
44   * @author Bruno Farache
45   */
46  public class LuceneIndexSearcherImpl implements IndexSearcher {
47  
48      public Hits search(
49              long companyId, Query query, Sort[] sorts, int start, int end)
50          throws SearchException {
51  
52          if (_log.isDebugEnabled()) {
53              _log.debug("Query " + query);
54          }
55  
56          Hits hits = null;
57  
58          org.apache.lucene.search.IndexSearcher searcher = null;
59          org.apache.lucene.search.Sort luceneSort = null;
60  
61          try {
62              searcher = LuceneHelperUtil.getSearcher(companyId, true);
63  
64              if (sorts != null) {
65                  SortField[] sortFields = new SortField[sorts.length];
66  
67                  for (int i = 0; i < sorts.length; i++) {
68                      Sort sort = sorts[i];
69  
70                      sortFields[i] = new SortField(
71                          sort.getFieldName(), sort.getType(), sort.isReverse());
72                  }
73  
74                  luceneSort = new org.apache.lucene.search.Sort(sortFields);
75              }
76  
77              long startTime = System.currentTimeMillis();
78  
79              org.apache.lucene.search.Hits luceneHits = searcher.search(
80                  QueryTranslator.translate(query), luceneSort);
81  
82              long endTime = System.currentTimeMillis();
83  
84              float searchTime = (float)(endTime - startTime) / Time.SECOND;
85  
86              hits = subset(luceneHits, query, startTime, searchTime, start, end);
87          }
88          catch (BooleanQuery.TooManyClauses tmc) {
89              int maxClauseCount = BooleanQuery.getMaxClauseCount();
90  
91              BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);
92  
93              try {
94                  long startTime = System.currentTimeMillis();
95  
96                  org.apache.lucene.search.Hits luceneHits = searcher.search(
97                      QueryTranslator.translate(query), luceneSort);
98  
99                  long endTime = System.currentTimeMillis();
100 
101                 float searchTime = (float)(endTime - startTime) / Time.SECOND;
102 
103                 hits = subset(
104                     luceneHits, query, startTime, searchTime, start, end);
105             }
106             catch (Exception e) {
107                 throw new SearchException(e);
108             }
109             finally {
110                 BooleanQuery.setMaxClauseCount(maxClauseCount);
111             }
112         }
113         catch (ParseException pe) {
114             _log.error("Query: " + query, pe);
115 
116             return new HitsImpl();
117         }
118         catch (Exception e) {
119             throw new SearchException(e);
120         }
121         finally {
122             try {
123                 if (searcher != null) {
124                     searcher.close();
125                 }
126             }
127             catch (IOException ioe) {
128                 throw new SearchException(ioe);
129             }
130         }
131 
132         if (_log.isDebugEnabled()) {
133             _log.debug(
134                 "Search found " + hits.getLength() + " results in " +
135                     hits.getSearchTime() + "ms");
136         }
137 
138         return hits;
139     }
140 
141     protected DocumentImpl getDocument(
142         org.apache.lucene.document.Document oldDoc) {
143 
144         DocumentImpl newDoc = new DocumentImpl();
145 
146         List<org.apache.lucene.document.Field> oldFields = oldDoc.getFields();
147 
148         for (org.apache.lucene.document.Field oldField : oldFields) {
149             String[] values = oldDoc.getValues(oldField.name());
150 
151             if ((values != null) && (values.length > 1)) {
152                 Field newField = new Field(
153                     oldField.name(), values, oldField.isTokenized());
154 
155                 newDoc.add(newField);
156             }
157             else {
158                 Field newField = new Field(
159                     oldField.name(), oldField.stringValue(),
160                     oldField.isTokenized());
161 
162                 newDoc.add(newField);
163             }
164         }
165 
166         return newDoc;
167     }
168 
169     protected String[] getQueryTerms(Query query) {
170         String[] queryTerms = new String[0];
171 
172         try {
173             queryTerms = LuceneHelperUtil.getQueryTerms(
174                 QueryTranslator.translate(query));
175         }
176         catch (ParseException pe) {
177             _log.error("Query: " + query, pe);
178         }
179 
180         return queryTerms;
181     }
182 
183     protected String getSnippet(
184             org.apache.lucene.document.Document doc, Query query, String field)
185         throws IOException {
186 
187         String[] values = doc.getValues(field);
188 
189         String snippet = null;
190 
191         if (Validator.isNull(values)) {
192             return snippet;
193         }
194 
195         String s = StringUtil.merge(values);
196 
197         try {
198             snippet = LuceneHelperUtil.getSnippet(
199                 QueryTranslator.translate(query), field, s);
200         }
201         catch (ParseException pe) {
202             _log.error("Query: " + query, pe);
203         }
204 
205         return snippet;
206     }
207 
208     protected Hits subset(
209             org.apache.lucene.search.Hits luceneHits, Query query,
210             long startTime, float searchTime, int start, int end)
211         throws IOException {
212 
213         int length = luceneHits.length();
214 
215         if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
216             start = 0;
217             end = length;
218         }
219 
220         String[] queryTerms = getQueryTerms(query);
221 
222         Hits subset = new HitsImpl();
223 
224         if ((start > - 1) && (start <= end)) {
225             if (end > length) {
226                 end = length;
227             }
228 
229             int subsetTotal = end - start;
230 
231             Document[] subsetDocs = new DocumentImpl[subsetTotal];
232             String[] subsetSnippets = new String[subsetTotal];
233             float[] subsetScores = new float[subsetTotal];
234 
235             int j = 0;
236 
237             for (int i = start; i < end; i++, j++) {
238                 org.apache.lucene.document.Document doc = luceneHits.doc(i);
239 
240                 subsetDocs[j] = getDocument(doc);
241                 subsetSnippets[j] = getSnippet(doc, query, Field.CONTENT);
242                 subsetScores[j] = luceneHits.score(i);
243             }
244 
245             subset.setStart(startTime);
246             subset.setSearchTime(searchTime);
247             subset.setQueryTerms(queryTerms);
248             subset.setDocs(subsetDocs);
249             subset.setLength(length);
250             subset.setSnippets(subsetSnippets);
251             subset.setScores(subsetScores);
252         }
253 
254         return subset;
255     }
256 
257     private static Log _log = LogFactoryUtil.getLog(
258         LuceneIndexSearcherImpl.class);
259 
260 }