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.StringBundler;
034 import com.liferay.portal.kernel.util.StringPool;
035 import com.liferay.portal.kernel.util.Validator;
036 import com.liferay.portal.search.lucene.LuceneHelperUtil;
037 import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
038 import com.liferay.portlet.documentlibrary.service.DLAppServiceUtil;
039 import com.liferay.util.lucene.KeywordsUtil;
040
041 import java.util.HashSet;
042 import java.util.Set;
043
044 import org.apache.lucene.analysis.Analyzer;
045 import org.apache.lucene.index.Term;
046 import org.apache.lucene.queryParser.QueryParser;
047
048
051 @DoPrivileged
052 public class RepositorySearchQueryBuilderImpl
053 implements RepositorySearchQueryBuilder {
054
055 @Override
056 public BooleanQuery getFullQuery(SearchContext searchContext)
057 throws SearchException {
058
059 try {
060 BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
061 searchContext);
062
063 addContext(contextQuery, searchContext);
064
065 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
066 searchContext);
067
068 addSearchKeywords(searchQuery, searchContext);
069
070 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(
071 searchContext);
072
073 if (contextQuery.hasClauses()) {
074 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
075 }
076
077 if (searchQuery.hasClauses()) {
078 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
079 }
080
081 BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
082
083 if (booleanClauses != null) {
084 for (BooleanClause booleanClause : booleanClauses) {
085 fullQuery.add(
086 booleanClause.getQuery(),
087 booleanClause.getBooleanClauseOccur());
088 }
089 }
090
091 fullQuery.setQueryConfig(searchContext.getQueryConfig());
092
093 return fullQuery;
094 }
095 catch (Exception e) {
096 throw new SearchException(e);
097 }
098 }
099
100 public void setAnalyzer(Analyzer analyzer) {
101 _analyzer = analyzer;
102 }
103
104 protected void addContext(
105 BooleanQuery contextQuery, SearchContext searchContext)
106 throws Exception {
107
108 long[] folderIds = searchContext.getFolderIds();
109
110 if ((folderIds == null) || (folderIds.length == 0)) {
111 return;
112 }
113
114 if (folderIds[0] == DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
115 return;
116 }
117
118 BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create(
119 searchContext);
120
121 for (long folderId : folderIds) {
122 try {
123 DLAppServiceUtil.getFolder(folderId);
124 }
125 catch (Exception e) {
126 continue;
127 }
128
129 folderIdsQuery.addTerm(Field.FOLDER_ID, folderId);
130 }
131
132 contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
133 }
134
135 protected void addSearchKeywords(
136 BooleanQuery searchQuery, SearchContext searchContext)
137 throws Exception {
138
139 String keywords = searchContext.getKeywords();
140
141 if (Validator.isNull(keywords)) {
142 return;
143 }
144
145 BooleanQuery titleQuery = BooleanQueryFactoryUtil.create(searchContext);
146
147 addTerm(titleQuery, searchContext, Field.TITLE, keywords);
148
149 if (titleQuery.hasClauses() && !contains(searchQuery, titleQuery)) {
150 searchQuery.add(titleQuery, BooleanClauseOccur.SHOULD);
151 }
152
153 BooleanQuery userNameQuery = BooleanQueryFactoryUtil.create(
154 searchContext);
155
156 addTerm(userNameQuery, searchContext, Field.USER_NAME, keywords);
157
158 if (userNameQuery.hasClauses() &&
159 !contains(searchQuery, userNameQuery)) {
160
161 searchQuery.add(userNameQuery, BooleanClauseOccur.SHOULD);
162 }
163
164 BooleanQuery contentQuery = BooleanQueryFactoryUtil.create(
165 searchContext);
166
167 addTerm(contentQuery, searchContext, Field.CONTENT, keywords);
168
169 if (contentQuery.hasClauses() && !contains(searchQuery, contentQuery)) {
170 searchQuery.add(contentQuery, BooleanClauseOccur.SHOULD);
171 }
172 }
173
174 protected void addTerm(
175 BooleanQuery booleanQuery, SearchContext searchContext, String field,
176 String value) {
177
178 if (Validator.isNull(value)) {
179 return;
180 }
181
182 try {
183 QueryParser queryParser = new QueryParser(
184 LuceneHelperUtil.getVersion(), field, _analyzer);
185
186 queryParser.setAllowLeadingWildcard(true);
187 queryParser.setLowercaseExpandedTerms(false);
188
189 org.apache.lucene.search.Query query = null;
190
191 try {
192 query = queryParser.parse(value);
193 }
194 catch (Exception e) {
195 query = queryParser.parse(KeywordsUtil.escape(value));
196 }
197
198 translateQuery(
199 booleanQuery, searchContext, query,
200 org.apache.lucene.search.BooleanClause.Occur.SHOULD);
201 }
202 catch (Exception e) {
203 _log.error(e, e);
204 }
205 }
206
207 protected boolean contains(Query query1, Query query2) {
208 if (query1 instanceof BooleanQuery) {
209 BooleanQuery booleanQuery = (BooleanQuery)query1;
210
211 for (com.liferay.portal.kernel.search.BooleanClause booleanClause :
212 booleanQuery.clauses()) {
213
214 if (contains(booleanClause.getQuery(), query2)) {
215 return true;
216 }
217 }
218
219 return false;
220 }
221 else if (query2 instanceof BooleanQuery) {
222 BooleanQuery booleanQuery = (BooleanQuery)query2;
223
224 for (com.liferay.portal.kernel.search.BooleanClause booleanClause :
225 booleanQuery.clauses()) {
226
227 if (contains(query1, booleanClause.getQuery())) {
228 return true;
229 }
230 }
231
232 return false;
233 }
234 else if ((query1 instanceof TermQuery) &&
235 (query2 instanceof TermQuery)) {
236
237 TermQuery termQuery1 = (TermQuery)query1;
238
239 QueryTerm queryTerm1 = termQuery1.getQueryTerm();
240
241 String field1 = queryTerm1.getField();
242 String value1 = queryTerm1.getValue();
243
244 TermQuery termQuery2 = (TermQuery)query2;
245
246 QueryTerm queryTerm2 = termQuery2.getQueryTerm();
247
248 String field2 = queryTerm2.getField();
249 String value2 = queryTerm2.getValue();
250
251 if (field1.equals(field2) && value1.equals(value2)) {
252 return true;
253 }
254 }
255 else if ((query1 instanceof TermRangeQuery) &&
256 (query2 instanceof TermRangeQuery)) {
257
258 TermRangeQuery termRangeQuery1 = (TermRangeQuery)query1;
259
260 boolean includesLower1 = termRangeQuery1.includesLower();
261 boolean includesUpper1 = termRangeQuery1.includesUpper();
262 String lowerTerm1 = termRangeQuery1.getLowerTerm();
263 String upperTerm1 = termRangeQuery1.getUpperTerm();
264
265 TermRangeQuery termRangeQuery2 = (TermRangeQuery)query2;
266
267 boolean includesLower2 = termRangeQuery2.includesLower();
268 boolean includesUpper2 = termRangeQuery2.includesUpper();
269 String lowerTerm2 = termRangeQuery2.getLowerTerm();
270 String upperTerm2 = termRangeQuery2.getUpperTerm();
271
272 if ((includesLower1 == includesLower2) &&
273 (includesUpper1 == includesUpper2) &&
274 lowerTerm1.equals(lowerTerm2) &&
275 upperTerm1.equals(upperTerm2)) {
276
277 return true;
278 }
279 }
280 else if ((query1 instanceof WildcardQuery) &&
281 (query2 instanceof WildcardQuery)) {
282
283 WildcardQuery wildcardQuery1 = (WildcardQuery)query1;
284
285 QueryTerm queryTerm1 = wildcardQuery1.getQueryTerm();
286
287 String field1 = queryTerm1.getField();
288 String value1 = queryTerm1.getValue();
289
290 WildcardQuery wildcardQuery2 = (WildcardQuery)query2;
291
292 QueryTerm queryTerm2 = wildcardQuery2.getQueryTerm();
293
294 String field2 = queryTerm2.getField();
295 String value2 = queryTerm2.getValue();
296
297 if (field1.equals(field2) && value1.equals(value2)) {
298 return true;
299 }
300 }
301
302 return false;
303 }
304
305 protected org.apache.lucene.search.BooleanClause.Occur
306 getBooleanClauseOccur(BooleanClauseOccur occur) {
307
308 if (occur.equals(BooleanClauseOccur.MUST)) {
309 return org.apache.lucene.search.BooleanClause.Occur.MUST;
310 }
311 else if (occur.equals(BooleanClauseOccur.MUST_NOT)) {
312 return org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
313 }
314
315 return org.apache.lucene.search.BooleanClause.Occur.SHOULD;
316 }
317
318 protected BooleanClauseOccur getBooleanClauseOccur(
319 org.apache.lucene.search.BooleanClause.Occur occur) {
320
321 if (occur.equals(org.apache.lucene.search.BooleanClause.Occur.MUST)) {
322 return BooleanClauseOccur.MUST;
323 }
324 else if (occur.equals(
325 org.apache.lucene.search.BooleanClause.Occur.MUST_NOT)) {
326
327 return BooleanClauseOccur.MUST_NOT;
328 }
329
330 return BooleanClauseOccur.SHOULD;
331 }
332
333 protected void translateQuery(
334 BooleanQuery booleanQuery, SearchContext searchContext,
335 org.apache.lucene.search.Query query,
336 org.apache.lucene.search.BooleanClause.Occur occur)
337 throws Exception {
338
339 BooleanClauseOccur booleanClauseOccur = getBooleanClauseOccur(occur);
340
341 if (query instanceof org.apache.lucene.search.TermQuery) {
342 Set<Term> terms = new HashSet<Term>();
343
344 query.extractTerms(terms);
345
346 for (Term term : terms) {
347 String termValue = term.text();
348
349 booleanQuery.addTerm(
350 term.field(), termValue, false,
351 getBooleanClauseOccur(occur));
352 }
353 }
354 else if (query instanceof org.apache.lucene.search.BooleanQuery) {
355 org.apache.lucene.search.BooleanQuery curBooleanQuery =
356 (org.apache.lucene.search.BooleanQuery)query;
357
358 BooleanQuery conjunctionQuery = BooleanQueryFactoryUtil.create(
359 searchContext);
360 BooleanQuery disjunctionQuery = BooleanQueryFactoryUtil.create(
361 searchContext);
362
363 for (org.apache.lucene.search.BooleanClause booleanClause :
364 curBooleanQuery.getClauses()) {
365
366 BooleanClauseOccur curBooleanClauseOccur =
367 getBooleanClauseOccur(booleanClause.getOccur());
368
369 BooleanQuery subbooleanQuery = null;
370
371 if (curBooleanClauseOccur.equals(BooleanClauseOccur.SHOULD)) {
372 subbooleanQuery = disjunctionQuery;
373 }
374 else {
375 subbooleanQuery = conjunctionQuery;
376 }
377
378 translateQuery(
379 subbooleanQuery, searchContext, booleanClause.getQuery(),
380 booleanClause.getOccur());
381
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 }