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