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 String getSearchEngineId(Collection<Document> documents) {
293 if (!documents.isEmpty()) {
294 Document document = documents.iterator().next();
295
296 return getSearchEngineId(document);
297 }
298
299 return getDefaultSearchEngineId();
300 }
301
302 public static String getSearchEngineId(Document document) {
303 String entryClassName = document.get("entryClassName");
304
305 Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
306
307 String searchEngineId = indexer.getSearchEngineId();
308
309 if (_log.isDebugEnabled()) {
310 _log.debug(
311 "Search engine ID for " + indexer.getClass() + " is " +
312 searchEngineId);
313 }
314
315 return searchEngineId;
316 }
317
318 public static Set<String> getSearchEngineIds() {
319 PortalRuntimePermission.checkGetBeanProperty(
320 SearchEngineUtil.class, "searchEngineIds");
321
322 return _searchEngines.keySet();
323 }
324
325 public static SearchEngine getSearchEngineSilent(String searchEngineId) {
326 PortalRuntimePermission.checkSearchEngine(searchEngineId);
327
328 return _searchEngines.get(searchEngineId);
329 }
330
331 public static SearchPermissionChecker getSearchPermissionChecker() {
332 PortalRuntimePermission.checkGetBeanProperty(
333 SearchEngineUtil.class, "searchPermissionChecker");
334
335 return _searchPermissionChecker;
336 }
337
338 public static String getSearchReaderDestinationName(String searchEngineId) {
339 return DestinationNames.SEARCH_READER.concat(StringPool.SLASH).concat(
340 searchEngineId);
341 }
342
343 public static String getSearchWriterDestinationName(String searchEngineId) {
344 return DestinationNames.SEARCH_WRITER.concat(StringPool.SLASH).concat(
345 searchEngineId);
346 }
347
348 public static void indexKeyword(
349 long companyId, String querySuggestion, float weight,
350 String keywordType, Locale locale)
351 throws SearchException {
352
353 String searchEngineId = getDefaultSearchEngineId();
354
355 indexKeyword(
356 searchEngineId, companyId, querySuggestion, weight, keywordType,
357 locale);
358 }
359
360 public static void indexKeyword(
361 String searchEngineId, long companyId, String querySuggestion,
362 float weight, String keywordType, Locale locale)
363 throws SearchException {
364
365 SearchEngine searchEngine = getSearchEngine(searchEngineId);
366
367 IndexWriter indexWriter = searchEngine.getIndexWriter();
368
369 SearchContext searchContext = new SearchContext();
370
371 searchContext.setCompanyId(companyId);
372 searchContext.setSearchEngineId(searchEngineId);
373 searchContext.setKeywords(querySuggestion);
374 searchContext.setLocale(locale);
375
376 indexWriter.indexKeyword(searchContext, weight, keywordType);
377 }
378
379 public static void indexQuerySuggestionDictionaries(long companyId)
380 throws SearchException {
381
382 Set<String> searchEngineIds = getSearchEngineIds();
383
384 for (String searchEngineId : searchEngineIds) {
385 indexQuerySuggestionDictionaries(searchEngineId, companyId);
386 }
387 }
388
389 public static void indexQuerySuggestionDictionaries(
390 String searchEngineId, long companyId)
391 throws SearchException {
392
393 SearchEngine searchEngine = getSearchEngine(searchEngineId);
394
395 IndexWriter indexWriter = searchEngine.getIndexWriter();
396
397 SearchContext searchContext = new SearchContext();
398
399 searchContext.setCompanyId(companyId);
400 searchContext.setSearchEngineId(searchEngineId);
401
402 indexWriter.indexQuerySuggestionDictionaries(searchContext);
403 }
404
405 public static void indexQuerySuggestionDictionary(
406 long companyId, Locale locale)
407 throws SearchException {
408
409 String searchEngineId = getDefaultSearchEngineId();
410
411 indexQuerySuggestionDictionary(searchEngineId, companyId, locale);
412 }
413
414 public static void indexQuerySuggestionDictionary(
415 String searchEngineId, long companyId, Locale locale)
416 throws SearchException {
417
418 SearchEngine searchEngine = getSearchEngine(searchEngineId);
419
420 IndexWriter indexWriter = searchEngine.getIndexWriter();
421
422 SearchContext searchContext = new SearchContext();
423
424 searchContext.setCompanyId(companyId);
425 searchContext.setSearchEngineId(searchEngineId);
426 searchContext.setLocale(locale);
427
428 indexWriter.indexQuerySuggestionDictionary(searchContext);
429 }
430
431 public static void indexSpellCheckerDictionaries(long companyId)
432 throws SearchException {
433
434 String searchEngineId = getDefaultSearchEngineId();
435
436 indexSpellCheckerDictionaries(searchEngineId, companyId);
437 }
438
439 public static void indexSpellCheckerDictionaries(
440 String searchEngineId, long companyId)
441 throws SearchException {
442
443 SearchEngine searchEngine = getSearchEngine(searchEngineId);
444
445 IndexWriter indexWriter = searchEngine.getIndexWriter();
446
447 SearchContext searchContext = new SearchContext();
448
449 searchContext.setCompanyId(companyId);
450 searchContext.setSearchEngineId(searchEngineId);
451
452 indexWriter.indexSpellCheckerDictionaries(searchContext);
453 }
454
455 public static void indexSpellCheckerDictionary(
456 long companyId, Locale locale)
457 throws SearchException {
458
459 String searchEngineId = getDefaultSearchEngineId();
460
461 indexSpellCheckerDictionary(searchEngineId, companyId, locale);
462 }
463
464 public static void indexSpellCheckerDictionary(
465 String searchEngineId, long companyId, Locale locale)
466 throws SearchException {
467
468 SearchEngine searchEngine = getSearchEngine(searchEngineId);
469
470 IndexWriter indexWriter = searchEngine.getIndexWriter();
471
472 SearchContext searchContext = new SearchContext();
473
474 searchContext.setCompanyId(companyId);
475 searchContext.setSearchEngineId(searchEngineId);
476 searchContext.setLocale(locale);
477
478 indexWriter.indexSpellCheckerDictionary(searchContext);
479 }
480
481 public static boolean isIndexReadOnly() {
482 PortalRuntimePermission.checkGetBeanProperty(
483 SearchEngineUtil.class, "indexReadOnly");
484
485 return _indexReadOnly;
486 }
487
488 public static SearchEngine removeSearchEngine(String searchEngineId) {
489 PortalRuntimePermission.checkSearchEngine(searchEngineId);
490
491 return _searchEngines.remove(searchEngineId);
492 }
493
494
497 public static Hits search(
498 long companyId, long[] groupIds, long userId, String className,
499 Query query, int start, int end)
500 throws SearchException {
501
502 SearchContext searchContext = new SearchContext();
503
504 searchContext.setSearchEngineId(getDefaultSearchEngineId());
505
506 if (userId > 0) {
507 query = _searchPermissionChecker.getPermissionQuery(
508 companyId, groupIds, userId, className, query, searchContext);
509 }
510
511 return search(
512 companyId, query, SortFactoryUtil.getDefaultSorts(), start, end);
513 }
514
515
518 public static Hits search(
519 long companyId, long[] groupIds, long userId, String className,
520 Query query, Sort sort, int start, int end)
521 throws SearchException {
522
523 SearchContext searchContext = new SearchContext();
524
525 searchContext.setSearchEngineId(getDefaultSearchEngineId());
526
527 if (userId > 0) {
528 query = _searchPermissionChecker.getPermissionQuery(
529 companyId, groupIds, userId, className, query, searchContext);
530 }
531
532 return search(companyId, query, sort, start, end);
533 }
534
535
538 public static Hits search(
539 long companyId, long[] groupIds, long userId, String className,
540 Query query, Sort[] sorts, int start, int end)
541 throws SearchException {
542
543 SearchContext searchContext = new SearchContext();
544
545 searchContext.setSearchEngineId(getDefaultSearchEngineId());
546
547 if (userId > 0) {
548 query = _searchPermissionChecker.getPermissionQuery(
549 companyId, groupIds, userId, className, query, searchContext);
550 }
551
552 return search(companyId, query, sorts, start, end);
553 }
554
555
559 public static Hits search(long companyId, Query query, int start, int end)
560 throws SearchException {
561
562 return search(getDefaultSearchEngineId(), companyId, query, start, end);
563 }
564
565
569 public static Hits search(
570 long companyId, Query query, Sort sort, int start, int end)
571 throws SearchException {
572
573 return search(
574 getDefaultSearchEngineId(), companyId, query, sort, start, end);
575 }
576
577
581 public static Hits search(
582 long companyId, Query query, Sort[] sorts, int start, int end)
583 throws SearchException {
584
585 return search(
586 getDefaultSearchEngineId(), companyId, query, sorts, start, end);
587 }
588
589 public static Hits search(SearchContext searchContext, Query query)
590 throws SearchException {
591
592 if (_log.isDebugEnabled()) {
593 _log.debug("Search query " + query.toString());
594 }
595
596 SearchEngine searchEngine = getSearchEngine(
597 searchContext.getSearchEngineId());
598
599 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
600
601 return indexSearcher.search(searchContext, query);
602 }
603
604 public static Hits search(
605 String searchEngineId, long companyId, Query query, int start,
606 int end)
607 throws SearchException {
608
609 if (_log.isDebugEnabled()) {
610 _log.debug("Search query " + query.toString());
611 }
612
613 SearchEngine searchEngine = getSearchEngine(searchEngineId);
614
615 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
616
617 return indexSearcher.search(
618 searchEngineId, companyId, query, SortFactoryUtil.getDefaultSorts(),
619 start, end);
620 }
621
622 public static Hits search(
623 String searchEngineId, long companyId, Query query, Sort sort,
624 int start, int end)
625 throws SearchException {
626
627 if (_log.isDebugEnabled()) {
628 _log.debug("Search query " + query.toString());
629 }
630
631 SearchEngine searchEngine = getSearchEngine(searchEngineId);
632
633 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
634
635 return indexSearcher.search(
636 searchEngineId, companyId, query, new Sort[] {sort}, start, end);
637 }
638
639 public static Hits search(
640 String searchEngineId, long companyId, Query query, Sort[] sorts,
641 int start, int end)
642 throws SearchException {
643
644 if (_log.isDebugEnabled()) {
645 _log.debug("Search query " + query.toString());
646 }
647
648 SearchEngine searchEngine = getSearchEngine(searchEngineId);
649
650 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
651
652 return indexSearcher.search(
653 searchEngineId, companyId, query, sorts, start, end);
654 }
655
656 public static void setDefaultSearchEngineId(String defaultSearchEngineId) {
657 PortalRuntimePermission.checkSetBeanProperty(
658 SearchEngineUtil.class, "defaultSearchEngineId");
659
660 _defaultSearchEngineId = defaultSearchEngineId;
661 }
662
663 public static void setIndexReadOnly(boolean indexReadOnly) {
664 PortalRuntimePermission.checkSetBeanProperty(
665 SearchEngineUtil.class, "indexReadOnly");
666
667 _indexReadOnly = indexReadOnly;
668 }
669
670 public static void setSearchEngine(
671 String searchEngineId, SearchEngine searchEngine) {
672
673 PortalRuntimePermission.checkSearchEngine(searchEngineId);
674
675 _searchEngines.put(searchEngineId, searchEngine);
676 }
677
678 public static String spellCheckKeywords(SearchContext searchContext)
679 throws SearchException {
680
681 if (_log.isDebugEnabled()) {
682 _log.debug("Spell checking " + searchContext.getKeywords());
683 }
684
685 SearchEngine searchEngine = getSearchEngine(
686 searchContext.getSearchEngineId());
687
688 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
689
690 return indexSearcher.spellCheckKeywords(searchContext);
691 }
692
693 public static Map<String, List<String>> spellCheckKeywords(
694 SearchContext searchContext, int max)
695 throws SearchException {
696
697 if (_log.isDebugEnabled()) {
698 _log.debug("Spell checking " + searchContext.getKeywords());
699 }
700
701 SearchEngine searchEngine = getSearchEngine(
702 searchContext.getSearchEngineId());
703
704 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
705
706 return indexSearcher.spellCheckKeywords(searchContext, max);
707 }
708
709 public static String[] suggestKeywordQueries(
710 SearchContext searchContext, int max)
711 throws SearchException {
712
713 if (_log.isDebugEnabled()) {
714 _log.debug(
715 "Suggesting keyword queries" + searchContext.getKeywords());
716 }
717
718 SearchEngine searchEngine = getSearchEngine(
719 searchContext.getSearchEngineId());
720
721 IndexSearcher indexSearcher = searchEngine.getIndexSearcher();
722
723 return indexSearcher.suggestKeywordQueries(searchContext, max);
724 }
725
726
730 public static void updateDocument(long companyId, Document document)
731 throws SearchException {
732
733 updateDocument(getSearchEngineId(document), companyId, document);
734 }
735
736 public static void updateDocument(
737 String searchEngineId, long companyId, Document document)
738 throws SearchException {
739
740 if (isIndexReadOnly()) {
741 return;
742 }
743
744 if (_log.isDebugEnabled()) {
745 _log.debug("Document " + document.toString());
746 }
747
748 SearchEngine searchEngine = getSearchEngine(searchEngineId);
749
750 IndexWriter indexWriter = searchEngine.getIndexWriter();
751
752 _searchPermissionChecker.addPermissionFields(companyId, document);
753
754 SearchContext searchContext = new SearchContext();
755
756 searchContext.setCompanyId(companyId);
757 searchContext.setSearchEngineId(searchEngineId);
758
759 indexWriter.updateDocument(searchContext, document);
760 }
761
762
766 public static void updateDocuments(
767 long companyId, Collection<Document> documents)
768 throws SearchException {
769
770 updateDocuments(getSearchEngineId(documents), companyId, documents);
771 }
772
773 public static void updateDocuments(
774 String searchEngineId, long companyId,
775 Collection<Document> documents)
776 throws SearchException {
777
778 if (isIndexReadOnly() || (documents == null) || documents.isEmpty()) {
779 return;
780 }
781
782 SearchEngine searchEngine = getSearchEngine(searchEngineId);
783
784 IndexWriter indexWriter = searchEngine.getIndexWriter();
785
786 for (Document document : documents) {
787 if (_log.isDebugEnabled()) {
788 _log.debug("Document " + document.toString());
789 }
790
791 _searchPermissionChecker.addPermissionFields(companyId, document);
792 }
793
794 SearchContext searchContext = new SearchContext();
795
796 searchContext.setCompanyId(companyId);
797 searchContext.setSearchEngineId(searchEngineId);
798
799 indexWriter.updateDocuments(searchContext, documents);
800 }
801
802 public static void updatePermissionFields(String name, String primKey) {
803 if (isIndexReadOnly() || !PermissionThreadLocal.isFlushEnabled()) {
804 return;
805 }
806
807 _searchPermissionChecker.updatePermissionFields(name, primKey);
808 }
809
810 public void setExcludedEntryClassNames(
811 List<String> excludedEntryClassNames) {
812
813 PortalRuntimePermission.checkSetBeanProperty(
814 getClass(), "excludedEntryClassNames");
815
816 _excludedEntryClassNames.addAll(excludedEntryClassNames);
817 }
818
819
823 public void setSearchEngine(SearchEngine searchEngine) {
824 String searchEngineId = getDefaultSearchEngineId();
825
826 PortalRuntimePermission.checkSearchEngine(searchEngineId);
827
828 _searchEngines.put(searchEngineId, searchEngine);
829 }
830
831 public void setSearchPermissionChecker(
832 SearchPermissionChecker searchPermissionChecker) {
833
834 PortalRuntimePermission.checkSetBeanProperty(
835 getClass(), "searchPermissionChecker");
836
837 _searchPermissionChecker = searchPermissionChecker;
838 }
839
840 private static Log _log = LogFactoryUtil.getLog(SearchEngineUtil.class);
841
842 private static String _defaultSearchEngineId;
843 private static Set<String> _excludedEntryClassNames = new HashSet<String>();
844 private static boolean _indexReadOnly = GetterUtil.getBoolean(
845 PropsUtil.get(PropsKeys.INDEX_READ_ONLY));
846 private static Map<String, SearchEngine> _searchEngines =
847 new ConcurrentHashMap<String, SearchEngine>();
848 private static SearchPermissionChecker _searchPermissionChecker;
849
850 }