001
014
015 package com.liferay.portal.kernel.search;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.messaging.DestinationNames;
020 import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.PropsKeys;
023 import com.liferay.portal.kernel.util.PropsUtil;
024 import com.liferay.portal.kernel.util.StringPool;
025 import com.liferay.portal.security.permission.PermissionThreadLocal;
026
027 import java.util.Collection;
028 import java.util.HashSet;
029 import java.util.List;
030 import java.util.Locale;
031 import java.util.Map;
032 import java.util.Set;
033 import java.util.concurrent.ConcurrentHashMap;
034
035
040 public class SearchEngineUtil {
041
042
046 public static final int ALL_POS = -1;
047
048 public static final String GENERIC_ENGINE_ID = "GENERIC_ENGINE";
049
050 public static final String SYSTEM_ENGINE_ID = "SYSTEM_ENGINE";
051
052
056 public static void addDocument(long companyId, Document document)
057 throws SearchException {
058
059 addDocument(_getSearchEngineId(document), companyId, document);
060 }
061
062 public static void addDocument(
063 String searchEngineId, long companyId, Document document)
064 throws SearchException {
065
066 if (isIndexReadOnly()) {
067 return;
068 }
069
070 if (_log.isDebugEnabled()) {
071 _log.debug("Add document " + document.toString());
072 }
073
074 SearchEngine searchEngine = getSearchEngine(searchEngineId);
075
076 IndexWriter indexWriter = searchEngine.getIndexWriter();
077
078 _searchPermissionChecker.addPermissionFields(companyId, document);
079
080 SearchContext searchContext = new SearchContext();
081
082 searchContext.setCompanyId(companyId);
083 searchContext.setSearchEngineId(searchEngineId);
084
085 indexWriter.addDocument(searchContext, document);
086 }
087
088
092 public static void addDocuments(
093 long companyId, Collection<Document> documents)
094 throws SearchException {
095
096 addDocuments(_getSearchEngineId(documents), companyId, documents);
097 }
098
099 public static void addDocuments(
100 String searchEngineId, long companyId,
101 Collection<Document> documents)
102 throws SearchException {
103
104 if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
105 return;
106 }
107
108 SearchEngine searchEngine = getSearchEngine(searchEngineId);
109
110 IndexWriter indexWriter = searchEngine.getIndexWriter();
111
112 for (Document document : documents) {
113 if (_log.isDebugEnabled()) {
114 _log.debug("Add document " + document.toString());
115 }
116
117 _searchPermissionChecker.addPermissionFields(companyId, document);
118 }
119
120 SearchContext searchContext = new SearchContext();
121
122 searchContext.setCompanyId(companyId);
123 searchContext.setSearchEngineId(searchEngineId);
124
125 indexWriter.addDocuments(searchContext, documents);
126 }
127
128
132 public static void addSearchEngine(SearchEngine searchEngine) {
133 String searchEngineId = getDefaultSearchEngineId();
134
135 PortalRuntimePermission.checkSearchEngine(searchEngineId);
136
137 _searchEngines.put(searchEngineId, searchEngine);
138 }
139
140
144 public static void deleteDocument(long companyId, String uid)
145 throws SearchException {
146
147 for (String searchEngineId : _searchEngines.keySet()) {
148 deleteDocument(searchEngineId, companyId, uid);
149 }
150 }
151
152 public static void deleteDocument(
153 String searchEngineId, long companyId, String uid)
154 throws SearchException {
155
156 if (isIndexReadOnly()) {
157 return;
158 }
159
160 SearchEngine searchEngine = getSearchEngine(searchEngineId);
161
162 IndexWriter indexWriter = searchEngine.getIndexWriter();
163
164 SearchContext searchContext = new SearchContext();
165
166 searchContext.setCompanyId(companyId);
167 searchContext.setSearchEngineId(searchEngineId);
168
169 indexWriter.deleteDocument(searchContext, uid);
170 }
171
172
176 public static void deleteDocuments(long companyId, Collection<String> uids)
177 throws SearchException {
178
179 for (String searchEngineId : _searchEngines.keySet()) {
180 deleteDocuments(searchEngineId, companyId, uids);
181 }
182 }
183
184 public static void deleteDocuments(
185 String searchEngineId, long companyId, Collection<String> uids)
186 throws SearchException {
187
188 if (isIndexReadOnly() || (uids == null) || uids.isEmpty()) {
189 return;
190 }
191
192 SearchEngine searchEngine = getSearchEngine(searchEngineId);
193
194 IndexWriter indexWriter = searchEngine.getIndexWriter();
195
196 SearchContext searchContext = new SearchContext();
197
198 searchContext.setCompanyId(companyId);
199 searchContext.setSearchEngineId(searchEngineId);
200
201 indexWriter.deleteDocuments(searchContext, uids);
202 }
203
204
208 public static void deletePortletDocuments(long companyId, String portletId)
209 throws SearchException {
210
211 for (String searchEngineId : _searchEngines.keySet()) {
212 deletePortletDocuments(searchEngineId, companyId, portletId);
213 }
214 }
215
216 public static void deletePortletDocuments(
217 String searchEngineId, long companyId, String portletId)
218 throws SearchException {
219
220 if (isIndexReadOnly()) {
221 return;
222 }
223
224 SearchEngine searchEngine = getSearchEngine(searchEngineId);
225
226 if (searchEngine == null) {
227 return;
228 }
229
230 IndexWriter indexWriter = searchEngine.getIndexWriter();
231
232 SearchContext searchContext = new SearchContext();
233
234 searchContext.setCompanyId(companyId);
235 searchContext.setSearchEngineId(searchEngineId);
236
237 indexWriter.deletePortletDocuments(searchContext, portletId);
238 }
239
240 public static String getDefaultSearchEngineId() {
241 if (_defaultSearchEngineId == null) {
242 return SYSTEM_ENGINE_ID;
243 }
244
245 return _defaultSearchEngineId;
246 }
247
248 public static String[] getEntryClassNames() {
249 Set<String> assetEntryClassNames = new HashSet<String>();
250
251 for (Indexer indexer : IndexerRegistryUtil.getIndexers()) {
252 for (String className : indexer.getClassNames()) {
253 if (!_excludedEntryClassNames.contains(className)) {
254 assetEntryClassNames.add(className);
255 }
256 }
257 }
258
259 return assetEntryClassNames.toArray(
260 new String[assetEntryClassNames.size()]);
261 }
262
263
266 public static SearchEngine getSearchEngine() {
267 return getSearchEngine(getDefaultSearchEngineId());
268 }
269
270 public static SearchEngine getSearchEngine(String searchEngineId) {
271 PortalRuntimePermission.checkSearchEngine(searchEngineId);
272
273 SearchEngine searchEngine = _searchEngines.get(searchEngineId);
274
275 if (searchEngine == null) {
276 if (getDefaultSearchEngineId().equals(searchEngineId)) {
277 throw new IllegalStateException(
278 "There is no default search engine configured with ID " +
279 getDefaultSearchEngineId());
280 }
281
282 if (_log.isWarnEnabled()) {
283 _log.warn(
284 "There is no search engine configured with ID " +
285 searchEngineId);
286 }
287 }
288
289 return searchEngine;
290 }
291
292 public static Set<String> getSearchEngineIds() {
293 PortalRuntimePermission.checkGetBeanProperty(
294 SearchEngineUtil.class, "searchEngineIds");
295
296 return _searchEngines.keySet();
297 }
298
299 public static SearchEngine getSearchEngineSilent(String searchEngineId) {
300 PortalRuntimePermission.checkSearchEngine(searchEngineId);
301
302 return _searchEngines.get(searchEngineId);
303 }
304
305 public static SearchPermissionChecker getSearchPermissionChecker() {
306 PortalRuntimePermission.checkGetBeanProperty(
307 SearchEngineUtil.class, "searchPermissionChecker");
308
309 return _searchPermissionChecker;
310 }
311
312 public static String getSearchReaderDestinationName(String searchEngineId) {
313 return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat(
314 searchEngineId);
315 }
316
317 public static String getSearchWriterDestinationName(String searchEngineId) {
318 return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat(
319 searchEngineId);
320 }
321
322 public static void indexQuerySuggestionDictionaries(long companyId)
323 throws SearchException {
324
325 Set<String> searchEngineIds = getSearchEngineIds();
326
327 for (String searchEngineId : searchEngineIds) {
328 indexQuerySuggestionDictionaries(searchEngineId, companyId);
329 }
330 }
331
332 public static void indexQuerySuggestionDictionaries(
333 String searchEngineId, long companyId)
334 throws SearchException {
335
336 SearchEngine searchEngine = getSearchEngine(searchEngineId);
337
338 IndexWriter indexWriter = searchEngine.getIndexWriter();
339
340 SearchContext searchContext = new SearchContext();
341
342 searchContext.setCompanyId(companyId);
343 searchContext.setSearchEngineId(searchEngineId);
344
345 indexWriter.indexQuerySuggestionDictionaries(searchContext);
346 }
347
348 public static void indexQuerySuggestionDictionary(
349 long companyId, Locale locale)
350 throws SearchException {
351
352 Set<String> searchEngineIds = getSearchEngineIds();
353
354 for (String searchEngineId : searchEngineIds) {
355 indexQuerySuggestionDictionary(searchEngineId, companyId, locale);
356 }
357 }
358
359 public static void indexQuerySuggestionDictionary(
360 String searchEngineId, long companyId, Locale locale)
361 throws SearchException {
362
363 SearchEngine searchEngine = getSearchEngine(searchEngineId);
364
365 IndexWriter indexWriter = searchEngine.getIndexWriter();
366
367 SearchContext searchContext = new SearchContext();
368
369 searchContext.setCompanyId(companyId);
370 searchContext.setSearchEngineId(searchEngineId);
371 searchContext.setLocale(locale);
372
373 indexWriter.indexQuerySuggestionDictionary(searchContext);
374 }
375
376 public static void indexSpellCheckerDictionaries(long companyId)
377 throws SearchException {
378
379 Set<String> searchEngineIds = getSearchEngineIds();
380
381 for (String searchEngineId : searchEngineIds) {
382 indexSpellCheckerDictionaries(searchEngineId, companyId);
383 }
384 }
385
386 public static void indexSpellCheckerDictionaries(
387 String searchEngineId, long companyId)
388 throws SearchException {
389
390 SearchEngine searchEngine = getSearchEngine(searchEngineId);
391
392 IndexWriter indexWriter = searchEngine.getIndexWriter();
393
394 SearchContext searchContext = new SearchContext();
395
396 searchContext.setCompanyId(companyId);
397 searchContext.setSearchEngineId(searchEngineId);
398
399 indexWriter.indexSpellCheckerDictionaries(searchContext);
400 }
401
402 public static void indexSpellCheckerDictionary(
403 long companyId, Locale locale)
404 throws SearchException {
405
406 Set<String> searchEngineIds = getSearchEngineIds();
407
408 for (String searchEngineId : searchEngineIds) {
409 indexSpellCheckerDictionary(searchEngineId, companyId, locale);
410 }
411 }
412
413 public static void indexSpellCheckerDictionary(
414 String searchEngineId, long companyId, Locale locale)
415 throws SearchException {
416
417 SearchEngine searchEngine = getSearchEngine(searchEngineId);
418
419 IndexWriter indexWriter = searchEngine.getIndexWriter();
420
421 SearchContext searchContext = new SearchContext();
422
423 searchContext.setCompanyId(companyId);
424 searchContext.setSearchEngineId(searchEngineId);
425 searchContext.setLocale(locale);
426
427 indexWriter.indexSpellCheckerDictionary(searchContext);
428 }
429
430 public static boolean isIndexReadOnly() {
431 PortalRuntimePermission.checkGetBeanProperty(
432 SearchEngineUtil.class, "indexReadOnly");
433
434 return _indexReadOnly;
435 }
436
437 public static SearchEngine removeSearchEngine(String searchEngineId) {
438 PortalRuntimePermission.checkSearchEngine(searchEngineId);
439
440 return _searchEngines.remove(searchEngineId);
441 }
442
443
446 public static Hits search(
447 long companyId, long[] groupIds, long userId, String className,
448 Query query, int start, int end)
449 throws SearchException {
450
451 SearchContext searchContext = new SearchContext();
452
453 searchContext.setSearchEngineId(getDefaultSearchEngineId());
454
455 if (userId > 0) {
456 query = _searchPermissionChecker.getPermissionQuery(
457 companyId, groupIds, userId, className, query, searchContext);
458 }
459
460 return search(
461 companyId, query, SortFactoryUtil.getDefaultSorts(), start, end);
462 }
463
464
467 public static Hits search(
468 long companyId, long[] groupIds, long userId, String className,
469 Query query, Sort sort, int start, int end)
470 throws SearchException {
471
472 SearchContext searchContext = new SearchContext();
473
474 searchContext.setSearchEngineId(getDefaultSearchEngineId());
475
476 if (userId > 0) {
477 query = _searchPermissionChecker.getPermissionQuery(
478 companyId, groupIds, userId, className, query, searchContext);
479 }
480
481 return search(companyId, query, sort, start, end);
482 }
483
484
487 public static Hits search(
488 long companyId, long[] groupIds, long userId, String className,
489 Query query, Sort[] sorts, int start, int end)
490 throws SearchException {
491
492 SearchContext searchContext = new SearchContext();
493
494 searchContext.setSearchEngineId(getDefaultSearchEngineId());
495
496 if (userId > 0) {
497 query = _searchPermissionChecker.getPermissionQuery(
498 companyId, groupIds, userId, className, query, searchContext);
499 }
500
501 return search(companyId, query, sorts, start, end);
502 }
503
504
508 public static Hits search(long companyId, Query query, int start, int end)
509 throws SearchException {
510
511 return search(getDefaultSearchEngineId(), companyId, query, start, end);
512 }
513
514
518 public static Hits search(
519 long companyId, Query query, Sort sort, int start, int end)
520 throws SearchException {
521
522 return search(
523 getDefaultSearchEngineId(), companyId, query, sort, start, end);
524 }
525
526
530 public static Hits search(
531 long companyId, Query query, Sort[] sorts, int start, int end)
532 throws SearchException {
533
534 return search(
535 getDefaultSearchEngineId(), companyId, query, sorts, start, end);
536 }
537
538 public static Hits search(SearchContext searchContext, Query query)
539 throws SearchException {
540
541 if (_log.isDebugEnabled()) {
542 _log.debug("Search query " + query.toString());
543 }
544
545 SearchEngine searchEngine = getSearchEngine(
546 searchContext.getSearchEngineId());
547
548 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
549
550 return indexSearcher.search(searchContext, query);
551 }
552
553 public static Hits search(
554 String searchEngineId, long companyId, Query query, int start,
555 int end)
556 throws SearchException {
557
558 if (_log.isDebugEnabled()) {
559 _log.debug("Search query " + query.toString());
560 }
561
562 SearchEngine searchEngine = getSearchEngine(searchEngineId);
563
564 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
565
566 return indexSearcher.search(
567 searchEngineId, companyId, query, SortFactoryUtil.getDefaultSorts(),
568 start, end);
569 }
570
571 public static Hits search(
572 String searchEngineId, long companyId, Query query, Sort sort,
573 int start, int end)
574 throws SearchException {
575
576 if (_log.isDebugEnabled()) {
577 _log.debug("Search query " + query.toString());
578 }
579
580 SearchEngine searchEngine = getSearchEngine(searchEngineId);
581
582 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
583
584 return indexSearcher.search(
585 searchEngineId, companyId, query, new Sort[] {sort}, start, end);
586 }
587
588 public static Hits search(
589 String searchEngineId, long companyId, Query query, Sort[] sorts,
590 int start, int end)
591 throws SearchException {
592
593 if (_log.isDebugEnabled()) {
594 _log.debug("Search query " + query.toString());
595 }
596
597 SearchEngine searchEngine = getSearchEngine(searchEngineId);
598
599 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
600
601 return indexSearcher.search(
602 searchEngineId, companyId, query, sorts, start, end);
603 }
604
605 public static void setDefaultSearchEngineId(String defaultSearchEngineId) {
606 PortalRuntimePermission.checkSetBeanProperty(
607 SearchEngineUtil.class, "defaultSearchEngineId");
608
609 _defaultSearchEngineId = defaultSearchEngineId;
610 }
611
612 public static void setIndexReadOnly(boolean indexReadOnly) {
613 PortalRuntimePermission.checkSetBeanProperty(
614 SearchEngineUtil.class, "indexReadOnly");
615
616 _indexReadOnly = indexReadOnly;
617 }
618
619 public static void setSearchEngine(
620 String searchEngineId, SearchEngine searchEngine) {
621
622 PortalRuntimePermission.checkSearchEngine(searchEngineId);
623
624 _searchEngines.put(searchEngineId, searchEngine);
625 }
626
627 public static String spellCheckKeywords(SearchContext searchContext)
628 throws SearchException {
629
630 if (_log.isDebugEnabled()) {
631 _log.debug("Spell checking " + searchContext.getKeywords());
632 }
633
634 SearchEngine searchEngine = getSearchEngine(
635 searchContext.getSearchEngineId());
636
637 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
638
639 return indexSearcher.spellCheckKeywords(searchContext);
640 }
641
642 public static Map<String, List<String>> spellCheckKeywords(
643 SearchContext searchContext, int max)
644 throws SearchException {
645
646 if (_log.isDebugEnabled()) {
647 _log.debug("Spell checking " + searchContext.getKeywords());
648 }
649
650 SearchEngine searchEngine = getSearchEngine(
651 searchContext.getSearchEngineId());
652
653 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
654
655 return indexSearcher.spellCheckKeywords(searchContext, max);
656 }
657
658 public static String[] suggestKeywordQueries(
659 SearchContext searchContext, int max)
660 throws SearchException {
661
662 if (_log.isDebugEnabled()) {
663 _log.debug(
664 "Suggesting keyword queries" + searchContext.getKeywords());
665 }
666
667 SearchEngine searchEngine = getSearchEngine(
668 searchContext.getSearchEngineId());
669
670 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
671
672 return indexSearcher.suggestKeywordQueries(searchContext, max);
673 }
674
675
679 public static void updateDocument(long companyId, Document document)
680 throws SearchException {
681
682 updateDocument(_getSearchEngineId(document), companyId, document);
683 }
684
685 public static void updateDocument(
686 String searchEngineId, long companyId, Document document)
687 throws SearchException {
688
689 if (isIndexReadOnly()) {
690 return;
691 }
692
693 if (_log.isDebugEnabled()) {
694 _log.debug("Document " + document.toString());
695 }
696
697 SearchEngine searchEngine = getSearchEngine(searchEngineId);
698
699 IndexWriter indexWriter = searchEngine.getIndexWriter();
700
701 _searchPermissionChecker.addPermissionFields(companyId, document);
702
703 SearchContext searchContext = new SearchContext();
704
705 searchContext.setCompanyId(companyId);
706 searchContext.setSearchEngineId(searchEngineId);
707
708 indexWriter.updateDocument(searchContext, document);
709 }
710
711
715 public static void updateDocuments(
716 long companyId, Collection<Document> documents)
717 throws SearchException {
718
719 updateDocuments(_getSearchEngineId(documents), companyId, documents);
720 }
721
722 public static void updateDocuments(
723 String searchEngineId, long companyId,
724 Collection<Document> documents)
725 throws SearchException {
726
727 if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
728 return;
729 }
730
731 SearchEngine searchEngine = getSearchEngine(searchEngineId);
732
733 IndexWriter indexWriter = searchEngine.getIndexWriter();
734
735 for (Document document : documents) {
736 if (_log.isDebugEnabled()) {
737 _log.debug("Document " + document.toString());
738 }
739
740 _searchPermissionChecker.addPermissionFields(companyId, document);
741 }
742
743 SearchContext searchContext = new SearchContext();
744
745 searchContext.setCompanyId(companyId);
746 searchContext.setSearchEngineId(searchEngineId);
747
748 indexWriter.updateDocuments(searchContext, documents);
749 }
750
751 public static void updatePermissionFields(String name, String primKey) {
752 if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
753 return;
754 }
755
756 _searchPermissionChecker.updatePermissionFields(name, primKey);
757 }
758
759 public void setExcludedEntryClassNames(
760 List<String> excludedEntryClassNames) {
761
762 PortalRuntimePermission.checkSetBeanProperty(
763 getClass(), "excludedEntryClassNames");
764
765 _excludedEntryClassNames.addAll(excludedEntryClassNames);
766 }
767
768
772 public void setSearchEngine(SearchEngine searchEngine) {
773 String searchEngineId = getDefaultSearchEngineId();
774
775 PortalRuntimePermission.checkSearchEngine(searchEngineId);
776
777 _searchEngines.put(searchEngineId, searchEngine);
778 }
779
780 public void setSearchPermissionChecker(
781 SearchPermissionChecker searchPermissionChecker) {
782
783 PortalRuntimePermission.checkSetBeanProperty(
784 getClass(), "searchPermissionChecker");
785
786 _searchPermissionChecker = searchPermissionChecker;
787 }
788
789 private static String _getSearchEngineId(Collection<Document> documents) {
790 if (!documents.isEmpty()) {
791 Document document = documents.iterator().next();
792
793 return _getSearchEngineId(document);
794 }
795
796 return getDefaultSearchEngineId();
797 }
798
799 private static String _getSearchEngineId(Document document) {
800 String entryClassName = document.get("entryClassName");
801
802 Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
803
804 String searchEngineId = indexer.getSearchEngineId();
805
806 if (_log.isDebugEnabled()) {
807 _log.debug(
808 "Search engine ID for " + indexer.getClass() + " is " +
809 searchEngineId);
810 }
811
812 return searchEngineId;
813 }
814
815 private static Log _log = LogFactoryUtil.getLog(SearchEngineUtil.class);
816
817 private static String _defaultSearchEngineId;
818 private static Set<String> _excludedEntryClassNames = new HashSet<String>();
819 private static boolean _indexReadOnly = GetterUtil.getBoolean(
820 PropsUtil.get(PropsKeys.INDEX_READ_ONLY));
821 private static Map<String, SearchEngine> _searchEngines =
822 new ConcurrentHashMap<String, SearchEngine>();
823 private static SearchPermissionChecker _searchPermissionChecker;
824
825 }