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