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