1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.search.lucene;
21  
22  import com.liferay.portal.kernel.dao.orm.QueryUtil;
23  import com.liferay.portal.kernel.log.Log;
24  import com.liferay.portal.kernel.log.LogFactoryUtil;
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.SearchException;
33  import com.liferay.portal.kernel.search.Sort;
34  import com.liferay.portal.kernel.util.Time;
35  
36  import java.io.IOException;
37  
38  import java.util.List;
39  
40  import org.apache.lucene.queryParser.ParseException;
41  import org.apache.lucene.search.BooleanQuery;
42  import org.apache.lucene.search.SortField;
43  
44  /**
45   * <a href="LuceneIndexSearcherImpl.java.html"><b><i>View Source</i></b></a>
46   *
47   * @author Bruno Farache
48   *
49   */
50  public class LuceneIndexSearcherImpl implements IndexSearcher {
51  
52      public Hits search(
53              long companyId, Query query, Sort[] sorts, int start, int end)
54          throws SearchException {
55  
56          if (_log.isDebugEnabled()) {
57              _log.debug("Query " + query);
58          }
59  
60          Hits hits = null;
61  
62          org.apache.lucene.search.IndexSearcher searcher = null;
63  
64          try {
65              searcher = LuceneUtil.getSearcher(companyId);
66  
67              org.apache.lucene.search.Sort luceneSort = null;
68  
69              if (sorts != null) {
70                  SortField[] sortFields = new SortField[sorts.length];
71  
72                  for (int i = 0; i < sorts.length; i++) {
73                      Sort sort = sorts[i];
74  
75                      sortFields[i] = new SortField(
76                          sort.getFieldName(), sort.getType(), sort.isReverse());
77                  }
78  
79                  luceneSort = new org.apache.lucene.search.Sort(sortFields);
80              }
81  
82              org.apache.lucene.search.Hits luceneHits = searcher.search(
83                  QueryTranslator.translate(query), luceneSort);
84  
85              hits = subset(luceneHits, start, end);
86          }
87          catch (Exception e) {
88              if (e instanceof BooleanQuery.TooManyClauses ||
89                  e instanceof ParseException) {
90  
91                  _log.error("Query: " + query, e);
92  
93                  return new HitsImpl();
94              }
95              else {
96                  throw new SearchException(e);
97              }
98          }
99          finally {
100             try {
101                 if (searcher != null) {
102                     searcher.close();
103                 }
104             }
105             catch (IOException ioe) {
106                 throw new SearchException(ioe);
107             }
108         }
109 
110         if (_log.isDebugEnabled()) {
111             _log.debug(
112                 "Search found " + hits.getLength() + " results in " +
113                     hits.getSearchTime() + "ms");
114         }
115 
116         return hits;
117     }
118 
119     protected DocumentImpl getDocument(
120         org.apache.lucene.document.Document oldDoc) {
121 
122         DocumentImpl newDoc = new DocumentImpl();
123 
124         List<org.apache.lucene.document.Field> oldFields = oldDoc.getFields();
125 
126         for (org.apache.lucene.document.Field oldField : oldFields) {
127             String[] values = oldDoc.getValues(oldField.name());
128 
129             if ((values != null) && (values.length > 1)) {
130                 Field newField = new Field(
131                     oldField.name(), values, oldField.isTokenized());
132 
133                 newDoc.add(newField);
134             }
135             else {
136                 Field newField = new Field(
137                     oldField.name(), oldField.stringValue(),
138                     oldField.isTokenized());
139 
140                 newDoc.add(newField);
141             }
142         }
143 
144         return newDoc;
145     }
146 
147     protected Hits subset(
148             org.apache.lucene.search.Hits luceneHits, int start, int end)
149         throws IOException {
150 
151         int length = luceneHits.length();
152 
153         if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
154             start = 0;
155             end = length;
156         }
157 
158         long startTime = System.currentTimeMillis();
159 
160         Hits subset = new HitsImpl();
161 
162         if ((start > - 1) && (start <= end)) {
163             if (end > length) {
164                 end = length;
165             }
166 
167             int subsetTotal = end - start;
168 
169             Document[] subsetDocs = new DocumentImpl[subsetTotal];
170             float[] subsetScores = new float[subsetTotal];
171 
172             int j = 0;
173 
174             for (int i = start; i < end; i++, j++) {
175                 subsetDocs[j] = getDocument(luceneHits.doc(i));
176                 subsetScores[j] = luceneHits.score(i);
177             }
178 
179             subset.setLength(length);
180             subset.setDocs(subsetDocs);
181             subset.setScores(subsetScores);
182             subset.setStart(startTime);
183 
184             float searchTime =
185                 (float)(System.currentTimeMillis() - startTime) / Time.SECOND;
186 
187             subset.setSearchTime(searchTime);
188         }
189 
190         return subset;
191     }
192 
193     private static Log _log =
194         LogFactoryUtil.getLog(LuceneIndexSearcherImpl.class);
195 
196 }