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