001
014
015 package com.liferay.portal.repository.search;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.repository.search.RepositorySearchQueryBuilder;
020 import com.liferay.portal.kernel.search.BooleanClause;
021 import com.liferay.portal.kernel.search.BooleanClauseOccur;
022 import com.liferay.portal.kernel.search.BooleanQuery;
023 import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
024 import com.liferay.portal.kernel.search.Field;
025 import com.liferay.portal.kernel.search.Query;
026 import com.liferay.portal.kernel.search.QueryTerm;
027 import com.liferay.portal.kernel.search.SearchContext;
028 import com.liferay.portal.kernel.search.SearchException;
029 import com.liferay.portal.kernel.search.TermQuery;
030 import com.liferay.portal.kernel.search.TermRangeQuery;
031 import com.liferay.portal.kernel.search.WildcardQuery;
032 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
033 import com.liferay.portal.kernel.util.ArrayUtil;
034 import com.liferay.portal.kernel.util.StringBundler;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.Validator;
037 import com.liferay.portal.search.lucene.LuceneHelperUtil;
038 import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
039 import com.liferay.portlet.documentlibrary.service.DLAppServiceUtil;
040 import com.liferay.util.lucene.KeywordsUtil;
041
042 import java.util.HashSet;
043 import java.util.Set;
044
045 import org.apache.lucene.analysis.Analyzer;
046 import org.apache.lucene.index.Term;
047 import org.apache.lucene.queryParser.QueryParser;
048
049
052 @DoPrivileged
053 public class RepositorySearchQueryBuilderImpl
054 implements RepositorySearchQueryBuilder {
055
056 @Override
057 public BooleanQuery getFullQuery(SearchContext searchContext)
058 throws SearchException {
059
060 try {
061 BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
062 searchContext);
063
064 addContext(contextQuery, searchContext);
065
066 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
067 searchContext);
068
069 addSearchKeywords(searchQuery, searchContext);
070
071 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(
072 searchContext);
073
074 if (contextQuery.hasClauses()) {
075 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
076 }
077
078 if (searchQuery.hasClauses()) {
079 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
080 }
081
082 BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
083
084 if (booleanClauses != null) {
085 for (BooleanClause booleanClause : booleanClauses) {
086 fullQuery.add(
087 booleanClause.getQuery(),
088 booleanClause.getBooleanClauseOccur());
089 }
090 }
091
092 fullQuery.setQueryConfig(searchContext.getQueryConfig());
093
094 return fullQuery;
095 }
096 catch (Exception e) {
097 throw new SearchException(e);
098 }
099 }
100
101 public void setAnalyzer(Analyzer analyzer) {
102 _analyzer = analyzer;
103 }
104
105 protected void addContext(
106 BooleanQuery contextQuery, SearchContext searchContext)
107 throws Exception {
108
109 long[] folderIds = searchContext.getFolderIds();
110
111 if (ArrayUtil.isEmpty(folderIds)) {
112 return;
113 }
114
115 if (folderIds[0] == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
116 return;
117 }
118
119 BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create(
120 searchContext);
121
122 for (long folderId : folderIds) {
123 try {
124 DLAppServiceUtil.getFolder(folderId);
125 }
126 catch (Exception e) {
127 continue;
128 }
129
130 folderIdsQuery.addTerm(Field.FOLDER_ID, folderId);
131 }
132
133 contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
134 }
135
136 protected void addSearchKeywords(
137 BooleanQuery searchQuery, SearchContext searchContext)
138 throws Exception {
139
140 String keywords = searchContext.getKeywords();
141
142 if (Validator.isNull(keywords)) {
143 return;
144 }
145
146 BooleanQuery titleQuery = BooleanQueryFactoryUtil.create(searchContext);
147
148 addTerm(titleQuery, searchContext, Field.TITLE, keywords);
149
150 if (titleQuery.hasClauses() && !contains(searchQuery, titleQuery)) {
151 searchQuery.add(titleQuery, BooleanClauseOccur.SHOULD);
152 }
153
154 BooleanQuery userNameQuery = BooleanQueryFactoryUtil.create(
155 searchContext);
156
157 addTerm(userNameQuery, searchContext, Field.USER_NAME, keywords);
158
159 if (userNameQuery.hasClauses() &&
160 !contains(searchQuery, userNameQuery)) {
161
162 searchQuery.add(userNameQuery, BooleanClauseOccur.SHOULD);
163 }
164
165 BooleanQuery contentQuery = BooleanQueryFactoryUtil.create(
166 searchContext);
167
168 addTerm(contentQuery, searchContext, Field.CONTENT, keywords);
169
170 if (contentQuery.hasClauses() && !contains(searchQuery, contentQuery)) {
171 searchQuery.add(contentQuery, BooleanClauseOccur.SHOULD);
172 }
173 }
174
175 protected void addTerm(
176 BooleanQuery booleanQuery, SearchContext searchContext, String field,
177 String value) {
178
179 if (Validator.isNull(value)) {
180 return;
181 }
182
183 try {
184 QueryParser queryParser = new QueryParser(
185 LuceneHelperUtil.getVersion(), field, _analyzer);
186
187 queryParser.setAllowLeadingWildcard(true);
188 queryParser.setLowercaseExpandedTerms(false);
189
190 org.apache.lucene.search.Query query = null;
191
192 try {
193 query = queryParser.parse(value);
194 }
195 catch (Exception e) {
196 query = queryParser.parse(KeywordsUtil.escape(value));
197 }
198
199 translateQuery(
200 booleanQuery, searchContext, query,
201 org.apache.lucene.search.BooleanClause.Occur.SHOULD);
202 }
203 catch (Exception e) {
204 _log.error(e, e);
205 }
206 }
207
208 protected boolean contains(Query query1, Query query2) {
209 if (query1 instanceof BooleanQuery) {
210 BooleanQuery booleanQuery = (BooleanQuery)query1;
211
212 for (com.liferay.portal.kernel.search.BooleanClause booleanClause :
213 booleanQuery.clauses()) {
214
215 if (contains(booleanClause.getQuery(), query2)) {
216 return true;
217 }
218 }
219
220 return false;
221 }
222 else if (query2 instanceof BooleanQuery) {
223 BooleanQuery booleanQuery = (BooleanQuery)query2;
224
225 for (com.liferay.portal.kernel.search.BooleanClause booleanClause :
226 booleanQuery.clauses()) {
227
228 if (contains(query1, booleanClause.getQuery())) {
229 return true;
230 }
231 }
232
233 return false;
234 }
235 else if ((query1 instanceof TermQuery) &&
236 (query2 instanceof TermQuery)) {
237
238 TermQuery termQuery1 = (TermQuery)query1;
239
240 QueryTerm queryTerm1 = termQuery1.getQueryTerm();
241
242 String field1 = queryTerm1.getField();
243 String value1 = queryTerm1.getValue();
244
245 TermQuery termQuery2 = (TermQuery)query2;
246
247 QueryTerm queryTerm2 = termQuery2.getQueryTerm();
248
249 String field2 = queryTerm2.getField();
250 String value2 = queryTerm2.getValue();
251
252 if (field1.equals(field2) && value1.equals(value2)) {
253 return true;
254 }
255 }
256 else if ((query1 instanceof TermRangeQuery) &&
257 (query2 instanceof TermRangeQuery)) {
258
259 TermRangeQuery termRangeQuery1 = (TermRangeQuery)query1;
260
261 boolean includesLower1 = termRangeQuery1.includesLower();
262 boolean includesUpper1 = termRangeQuery1.includesUpper();
263 String lowerTerm1 = termRangeQuery1.getLowerTerm();
264 String upperTerm1 = termRangeQuery1.getUpperTerm();
265
266 TermRangeQuery termRangeQuery2 = (TermRangeQuery)query2;
267
268 boolean includesLower2 = termRangeQuery2.includesLower();
269 boolean includesUpper2 = termRangeQuery2.includesUpper();
270 String lowerTerm2 = termRangeQuery2.getLowerTerm();
271 String upperTerm2 = termRangeQuery2.getUpperTerm();
272
273 if ((includesLower1 == includesLower2) &&
274 (includesUpper1 == includesUpper2) &&
275 lowerTerm1.equals(lowerTerm2) &&
276 upperTerm1.equals(upperTerm2)) {
277
278 return true;
279 }
280 }
281 else if ((query1 instanceof WildcardQuery) &&
282 (query2 instanceof WildcardQuery)) {
283
284 WildcardQuery wildcardQuery1 = (WildcardQuery)query1;
285
286 QueryTerm queryTerm1 = wildcardQuery1.getQueryTerm();
287
288 String field1 = queryTerm1.getField();
289 String value1 = queryTerm1.getValue();
290
291 WildcardQuery wildcardQuery2 = (WildcardQuery)query2;
292
293 QueryTerm queryTerm2 = wildcardQuery2.getQueryTerm();
294
295 String field2 = queryTerm2.getField();
296 String value2 = queryTerm2.getValue();
297
298 if (field1.equals(field2) && value1.equals(value2)) {
299 return true;
300 }
301 }
302
303 return false;
304 }
305
306 protected org.apache.lucene.search.BooleanClause.Occur
307 getBooleanClauseOccur(BooleanClauseOccur occur) {
308
309 if (occur.equals(BooleanClauseOccur.MUST)) {
310 return org.apache.lucene.search.BooleanClause.Occur.MUST;
311 }
312 else if (occur.equals(BooleanClauseOccur.MUST_NOT)) {
313 return org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
314 }
315
316 return org.apache.lucene.search.BooleanClause.Occur.SHOULD;
317 }
318
319 protected BooleanClauseOccur getBooleanClauseOccur(
320 org.apache.lucene.search.BooleanClause.Occur occur) {
321
322 if (occur.equals(org.apache.lucene.search.BooleanClause.Occur.MUST)) {
323 return BooleanClauseOccur.MUST;
324 }
325 else if (occur.equals(
326 org.apache.lucene.search.BooleanClause.Occur.MUST_NOT)) {
327
328 return BooleanClauseOccur.MUST_NOT;
329 }
330
331 return BooleanClauseOccur.SHOULD;
332 }
333
334 protected void translateQuery(
335 BooleanQuery booleanQuery, SearchContext searchContext,
336 org.apache.lucene.search.Query query,
337 org.apache.lucene.search.BooleanClause.Occur occur)
338 throws Exception {
339
340 BooleanClauseOccur booleanClauseOccur = getBooleanClauseOccur(occur);
341
342 if (query instanceof org.apache.lucene.search.TermQuery) {
343 Set<Term> terms = new HashSet<Term>();
344
345 query.extractTerms(terms);
346
347 for (Term term : terms) {
348 String termValue = term.text();
349
350 booleanQuery.addTerm(
351 term.field(), termValue, false,
352 getBooleanClauseOccur(occur));
353 }
354 }
355 else if (query instanceof org.apache.lucene.search.BooleanQuery) {
356 org.apache.lucene.search.BooleanQuery curBooleanQuery =
357 (org.apache.lucene.search.BooleanQuery)query;
358
359 BooleanQuery conjunctionQuery = BooleanQueryFactoryUtil.create(
360 searchContext);
361 BooleanQuery disjunctionQuery = BooleanQueryFactoryUtil.create(
362 searchContext);
363
364 for (org.apache.lucene.search.BooleanClause booleanClause :
365 curBooleanQuery.getClauses()) {
366
367 BooleanClauseOccur curBooleanClauseOccur =
368 getBooleanClauseOccur(booleanClause.getOccur());
369
370 BooleanQuery subbooleanQuery = null;
371
372 if (curBooleanClauseOccur.equals(BooleanClauseOccur.SHOULD)) {
373 subbooleanQuery = disjunctionQuery;
374 }
375 else {
376 subbooleanQuery = conjunctionQuery;
377 }
378
379 translateQuery(
380 subbooleanQuery, searchContext, booleanClause.getQuery(),
381 booleanClause.getOccur());
382 }
383
384 if (conjunctionQuery.hasClauses()) {
385 booleanQuery.add(conjunctionQuery, BooleanClauseOccur.MUST);
386 }
387
388 if (disjunctionQuery.hasClauses()) {
389 booleanQuery.add(disjunctionQuery, BooleanClauseOccur.SHOULD);
390 }
391 }
392 else if (query instanceof org.apache.lucene.search.FuzzyQuery) {
393 org.apache.lucene.search.FuzzyQuery fuzzyQuery =
394 (org.apache.lucene.search.FuzzyQuery)query;
395
396 Term term = fuzzyQuery.getTerm();
397
398 String termValue = term.text().concat(StringPool.STAR);
399
400 booleanQuery.addTerm(
401 term.field(), termValue, true, booleanClauseOccur);
402 }
403 else if (query instanceof org.apache.lucene.search.PhraseQuery) {
404 org.apache.lucene.search.PhraseQuery phraseQuery =
405 (org.apache.lucene.search.PhraseQuery)query;
406
407 Term[] terms = phraseQuery.getTerms();
408
409 StringBundler sb = new StringBundler(terms.length * 2);
410
411 for (Term term : terms) {
412 sb.append(term.text());
413 sb.append(StringPool.SPACE);
414 }
415
416 booleanQuery.addTerm(
417 terms[0].field(), sb.toString().trim(), false,
418 booleanClauseOccur);
419 }
420 else if (query instanceof org.apache.lucene.search.PrefixQuery) {
421 org.apache.lucene.search.PrefixQuery prefixQuery =
422 (org.apache.lucene.search.PrefixQuery)query;
423
424 Term prefixTerm = prefixQuery.getPrefix();
425
426 String termValue = prefixTerm.text().concat(StringPool.STAR);
427
428 booleanQuery.addTerm(
429 prefixTerm.field(), termValue, true, booleanClauseOccur);
430 }
431 else if (query instanceof org.apache.lucene.search.TermRangeQuery) {
432 org.apache.lucene.search.TermRangeQuery termRangeQuery =
433 (org.apache.lucene.search.TermRangeQuery)query;
434
435 booleanQuery.addRangeTerm(
436 termRangeQuery.getField(), termRangeQuery.getLowerTerm(),
437 termRangeQuery.getUpperTerm());
438 }
439 else if (query instanceof org.apache.lucene.search.WildcardQuery) {
440 org.apache.lucene.search.WildcardQuery wildcardQuery =
441 (org.apache.lucene.search.WildcardQuery)query;
442
443 Term wildcardTerm = wildcardQuery.getTerm();
444
445 booleanQuery.addTerm(
446 wildcardTerm.field(), wildcardTerm.text(), true,
447 booleanClauseOccur);
448 }
449 else {
450 if (_log.isWarnEnabled()) {
451 _log.warn(
452 "Ignoring unknown query type " + query.getClass() +
453 " with query " + query);
454 }
455 }
456 }
457
458 private static Log _log = LogFactoryUtil.getLog(
459 RepositorySearchQueryBuilderImpl.class);
460
461 private Analyzer _analyzer;
462
463 }