1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.search.lucene;
24  
25  import com.liferay.portal.kernel.search.Document;
26  import com.liferay.portal.kernel.search.DocumentImpl;
27  import com.liferay.portal.kernel.search.Field;
28  import com.liferay.portal.kernel.search.Hits;
29  import com.liferay.portal.kernel.search.HitsImpl;
30  import com.liferay.portal.kernel.search.IndexSearcher;
31  import com.liferay.portal.kernel.search.Query;
32  import com.liferay.portal.kernel.search.SearchEngineUtil;
33  import com.liferay.portal.kernel.search.SearchException;
34  import com.liferay.portal.kernel.search.Sort;
35  import com.liferay.portal.kernel.util.GetterUtil;
36  import com.liferay.portal.kernel.util.Time;
37  
38  import java.io.IOException;
39  
40  import java.util.List;
41  
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  import org.apache.lucene.queryParser.ParseException;
45  import org.apache.lucene.search.BooleanQuery;
46  import org.apache.lucene.search.SortField;
47  
48  /**
49   * <a href="LuceneIndexSearcherImpl.java.html"><b><i>View Source</i></b></a>
50   *
51   * @author Bruno Farache
52   *
53   */
54  public class LuceneIndexSearcherImpl implements IndexSearcher {
55  
56      public Hits search(long companyId, Query query, int start, int end)
57          throws SearchException {
58  
59          return search(companyId, query, null, start, end);
60      }
61  
62      public Hits search(
63              long companyId, Query query, Sort sort, int start, int end)
64          throws SearchException {
65  
66          if (_log.isDebugEnabled()) {
67              _log.debug("Query: " + query);
68          }
69  
70          Hits hits = null;
71  
72          org.apache.lucene.search.IndexSearcher searcher = null;
73  
74          try {
75              searcher = LuceneUtil.getSearcher(companyId);
76  
77              org.apache.lucene.search.Sort luceneSort = null;
78  
79              if (sort != null) {
80                  luceneSort = new org.apache.lucene.search.Sort(
81                      new SortField(sort.getFieldName(), sort.isReverse()));
82              }
83  
84              org.apache.lucene.search.Hits luceneHits = searcher.search(
85                  QueryTranslator.translate(query), luceneSort);
86  
87              hits = subset(luceneHits, start, end);
88          }
89          catch (RuntimeException re) {
90  
91              // Trying to sort on a field when there are no results throws a
92              // RuntimeException that should not be rethrown
93  
94              String msg = GetterUtil.getString(re.getMessage());
95  
96              if (!msg.endsWith("does not appear to be indexed")) {
97                  throw re;
98              }
99          }
100         catch (Exception e) {
101             if (e instanceof BooleanQuery.TooManyClauses ||
102                 e instanceof ParseException) {
103 
104                 _log.error("Query: " + query, e);
105 
106                 return new HitsImpl();
107             }
108             else {
109                 throw new SearchException(e);
110             }
111         }
112         finally {
113             try {
114                 if (searcher != null) {
115                     searcher.close();
116                 }
117             }
118             catch (IOException ioe) {
119                 throw new SearchException(ioe);
120             }
121         }
122 
123         return hits;
124     }
125 
126     protected DocumentImpl getDocument(
127         org.apache.lucene.document.Document oldDoc) {
128 
129         DocumentImpl newDoc = new DocumentImpl();
130 
131         List<org.apache.lucene.document.Field> oldFields = oldDoc.getFields();
132 
133         for (org.apache.lucene.document.Field oldField : oldFields) {
134             String[] values = oldDoc.getValues(oldField.name());
135 
136             if ((values != null) && (values.length > 1)) {
137                 Field newField = new Field(
138                     oldField.name(), values, oldField.isTokenized());
139 
140                 newDoc.add(newField);
141             }
142             else {
143                 Field newField = new Field(
144                     oldField.name(), oldField.stringValue(),
145                     oldField.isTokenized());
146 
147                 newDoc.add(newField);
148             }
149         }
150 
151         return newDoc;
152     }
153 
154     protected Hits subset(
155             org.apache.lucene.search.Hits luceneHits, int start, int end)
156         throws IOException {
157 
158         int length = luceneHits.length();
159 
160         if ((start == SearchEngineUtil.ALL_POS) &&
161             (end == SearchEngineUtil.ALL_POS)) {
162 
163             start = 0;
164             end = length;
165         }
166 
167         long startTime = System.currentTimeMillis();
168 
169         Hits subset = new HitsImpl();
170 
171         if ((start > - 1) && (start <= end)) {
172             if (end > length) {
173                 end = length;
174             }
175 
176             int subsetTotal = end - start;
177 
178             Document[] subsetDocs = new DocumentImpl[subsetTotal];
179             float[] subsetScores = new float[subsetTotal];
180 
181             int j = 0;
182 
183             for (int i = start; i < end; i++, j++) {
184                 subsetDocs[j] = getDocument(luceneHits.doc(i));
185                 subsetScores[j] = luceneHits.score(i);
186             }
187 
188             subset.setLength(length);
189             subset.setDocs(subsetDocs);
190             subset.setScores(subsetScores);
191             subset.setStart(startTime);
192 
193             float searchTime =
194                 (float)(System.currentTimeMillis() - startTime) / Time.SECOND;
195 
196             subset.setSearchTime(searchTime);
197         }
198 
199         return subset;
200     }
201 
202     private static Log _log = LogFactory.getLog(LuceneIndexSearcherImpl.class);
203 
204 }