1
22
23 package com.liferay.portal.search.lucene;
24
25 import com.liferay.portal.kernel.dao.orm.QueryUtil;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.search.Document;
29 import com.liferay.portal.kernel.search.DocumentImpl;
30 import com.liferay.portal.kernel.search.Field;
31 import com.liferay.portal.kernel.search.Hits;
32 import com.liferay.portal.kernel.search.HitsImpl;
33 import com.liferay.portal.kernel.search.IndexSearcher;
34 import com.liferay.portal.kernel.search.Query;
35 import com.liferay.portal.kernel.search.SearchException;
36 import com.liferay.portal.kernel.search.Sort;
37 import com.liferay.portal.kernel.util.StringUtil;
38 import com.liferay.portal.kernel.util.Time;
39 import com.liferay.portal.kernel.util.Validator;
40
41 import java.io.IOException;
42
43 import java.util.List;
44
45 import org.apache.lucene.queryParser.ParseException;
46 import org.apache.lucene.search.BooleanQuery;
47 import org.apache.lucene.search.SortField;
48
49
54 public class LuceneIndexSearcherImpl implements IndexSearcher {
55
56 public Hits search(
57 long companyId, Query query, Sort[] sorts, int start, int end)
58 throws SearchException {
59
60 if (_log.isDebugEnabled()) {
61 _log.debug("Query " + query);
62 }
63
64 Hits hits = null;
65
66 org.apache.lucene.search.IndexSearcher searcher = null;
67 org.apache.lucene.search.Sort luceneSort = null;
68
69 try {
70 searcher = LuceneHelperUtil.getSearcher(companyId, true);
71
72 if (sorts != null) {
73 SortField[] sortFields = new SortField[sorts.length];
74
75 for (int i = 0; i < sorts.length; i++) {
76 Sort sort = sorts[i];
77
78 sortFields[i] = new SortField(
79 sort.getFieldName(), sort.getType(), sort.isReverse());
80 }
81
82 luceneSort = new org.apache.lucene.search.Sort(sortFields);
83 }
84
85 long startTime = System.currentTimeMillis();
86
87 org.apache.lucene.search.Hits luceneHits = searcher.search(
88 QueryTranslator.translate(query), luceneSort);
89
90 long endTime = System.currentTimeMillis();
91
92 float searchTime = (float)(endTime - startTime) / Time.SECOND;
93
94 hits = subset(luceneHits, query, startTime, searchTime, start, end);
95 }
96 catch (BooleanQuery.TooManyClauses tmc) {
97 int maxClauseCount = BooleanQuery.getMaxClauseCount();
98
99 BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);
100
101 try {
102 long startTime = System.currentTimeMillis();
103
104 org.apache.lucene.search.Hits luceneHits = searcher.search(
105 QueryTranslator.translate(query), luceneSort);
106
107 long endTime = System.currentTimeMillis();
108
109 float searchTime = (float)(endTime - startTime) / Time.SECOND;
110
111 hits = subset(
112 luceneHits, query, startTime, searchTime, start, end);
113 }
114 catch (Exception e) {
115 throw new SearchException(e);
116 }
117 finally {
118 BooleanQuery.setMaxClauseCount(maxClauseCount);
119 }
120 }
121 catch (ParseException pe) {
122 _log.error("Query: " + query, pe);
123
124 return new HitsImpl();
125 }
126 catch (Exception e) {
127 throw new SearchException(e);
128 }
129 finally {
130 try {
131 if (searcher != null) {
132 searcher.close();
133 }
134 }
135 catch (IOException ioe) {
136 throw new SearchException(ioe);
137 }
138 }
139
140 if (_log.isDebugEnabled()) {
141 _log.debug(
142 "Search found " + hits.getLength() + " results in " +
143 hits.getSearchTime() + "ms");
144 }
145
146 return hits;
147 }
148
149 protected DocumentImpl getDocument(
150 org.apache.lucene.document.Document oldDoc) {
151
152 DocumentImpl newDoc = new DocumentImpl();
153
154 List<org.apache.lucene.document.Field> oldFields = oldDoc.getFields();
155
156 for (org.apache.lucene.document.Field oldField : oldFields) {
157 String[] values = oldDoc.getValues(oldField.name());
158
159 if ((values != null) && (values.length > 1)) {
160 Field newField = new Field(
161 oldField.name(), values, oldField.isTokenized());
162
163 newDoc.add(newField);
164 }
165 else {
166 Field newField = new Field(
167 oldField.name(), oldField.stringValue(),
168 oldField.isTokenized());
169
170 newDoc.add(newField);
171 }
172 }
173
174 return newDoc;
175 }
176
177 protected String[] getQueryTerms(Query query) {
178 String[] queryTerms = new String[0];
179
180 try {
181 queryTerms = LuceneHelperUtil.getQueryTerms(
182 QueryTranslator.translate(query));
183 }
184 catch (ParseException pe) {
185 _log.error("Query: " + query, pe);
186 }
187
188 return queryTerms;
189 }
190
191 protected String getSnippet(
192 org.apache.lucene.document.Document doc, Query query, String field)
193 throws IOException {
194
195 String[] values = doc.getValues(field);
196
197 String snippet = null;
198
199 if (Validator.isNull(values)) {
200 return snippet;
201 }
202
203 String s = StringUtil.merge(values);
204
205 try {
206 snippet = LuceneHelperUtil.getSnippet(
207 QueryTranslator.translate(query), field, s);
208 }
209 catch (ParseException pe) {
210 _log.error("Query: " + query, pe);
211 }
212
213 return snippet;
214 }
215
216 protected Hits subset(
217 org.apache.lucene.search.Hits luceneHits, Query query,
218 long startTime, float searchTime, int start, int end)
219 throws IOException {
220
221 int length = luceneHits.length();
222
223 if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
224 start = 0;
225 end = length;
226 }
227
228 String[] queryTerms = getQueryTerms(query);
229
230 Hits subset = new HitsImpl();
231
232 if ((start > - 1) && (start <= end)) {
233 if (end > length) {
234 end = length;
235 }
236
237 int subsetTotal = end - start;
238
239 Document[] subsetDocs = new DocumentImpl[subsetTotal];
240 String[] subsetSnippets = new String[subsetTotal];
241 float[] subsetScores = new float[subsetTotal];
242
243 int j = 0;
244
245 for (int i = start; i < end; i++, j++) {
246 org.apache.lucene.document.Document doc = luceneHits.doc(i);
247
248 subsetDocs[j] = getDocument(doc);
249 subsetSnippets[j] = getSnippet(doc, query, Field.CONTENT);
250 subsetScores[j] = luceneHits.score(i);
251 }
252
253 subset.setStart(startTime);
254 subset.setSearchTime(searchTime);
255 subset.setQueryTerms(queryTerms);
256 subset.setDocs(subsetDocs);
257 subset.setLength(length);
258 subset.setSnippets(subsetSnippets);
259 subset.setScores(subsetScores);
260 }
261
262 return subset;
263 }
264
265 private static Log _log =
266 LogFactoryUtil.getLog(LuceneIndexSearcherImpl.class);
267
268 }