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