3ffa0ff757c9aae8b9b00532adff358a622edaef
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / search / LuceneMultiSearch.java
1 // $Id$
2 /**
3 * Copyright (C) 2011 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.cdm.api.service.search;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Set;
17
18 import org.apache.log4j.Logger;
19 import org.apache.lucene.analysis.Analyzer;
20 import org.apache.lucene.index.IndexReader;
21 import org.apache.lucene.index.MultiReader;
22 import org.apache.lucene.search.BooleanClause.Occur;
23 import org.apache.lucene.search.BooleanQuery;
24 import org.apache.lucene.search.IndexSearcher;
25 import org.hibernate.search.Search;
26 import org.hibernate.search.SearchFactory;
27 import org.hibernate.search.indexes.IndexReaderAccessor;
28
29 import eu.etaxonomy.cdm.model.common.CdmBase;
30
31 /**
32 * A LuceneSearch which allow to run a union like search on multiple indexes at once.
33 * Internally a {@link MultiReader} is being used.
34 *
35 * @author Andreas Kohlbecker
36 * @date Dec 21, 2011
37 *
38 */
39 public class LuceneMultiSearch extends LuceneSearch {
40
41 public static final Logger logger = Logger.getLogger(LuceneMultiSearch.class);
42
43 private final Set<Class<? extends CdmBase>> directorySelectClasses = new HashSet<Class<? extends CdmBase>>();
44
45
46 /**
47 * @param luceneSearch the searches to execute together as a union like search
48 * @throws Exception
49 */
50 public LuceneMultiSearch(LuceneSearch... luceneSearch) throws LuceneMultiSearchException {
51 session = luceneSearch[0].session;
52
53 BooleanQuery query = new BooleanQuery();
54
55 Set<String> highlightFields = new HashSet<String>();
56
57 for(LuceneSearch search : luceneSearch){
58 this.directorySelectClasses.add(search.getDirectorySelectClass());
59 query.add(search.getQuery(), Occur.SHOULD);
60 highlightFields.addAll(Arrays.asList(search.getHighlightFields()));
61 if(search.getClazz() != null){
62 if(getClazz() != null){
63 throw new LuceneMultiSearchException("LuceneMultiSearch can only handle once class restriction, but multiple given: " + getClazz() + ", " + search.getClazz());
64 }
65 setClazz(search.getClazz());
66 }
67 }
68
69 this.highlightFields = highlightFields.toArray(new String[highlightFields.size()]);
70 this.query = query;
71 }
72
73 /**
74 * @return
75 */
76 @Override
77 public IndexSearcher getSearcher() {
78
79 if(searcher == null){
80
81 SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
82 List<IndexReader> readers = new ArrayList<IndexReader>();
83 for(Class<? extends CdmBase> type : directorySelectClasses){
84 //OLD
85 // DirectoryProvider[] directoryProviders = searchFactory.getDirectoryProviders(type);
86 // logger.info(directoryProviders[0].getDirectory().toString());
87
88 // ReaderProvider readerProvider = searchFactory.getReaderProvider();
89 IndexReaderAccessor ira = searchFactory.getIndexReaderAccessor();
90 IndexReader reader = ira.open(type);
91 // readers.add(readerProvider.openReader(directoryProviders[0]));
92 readers.add(reader);
93 }
94 if(readers.size() > 1){
95 MultiReader multireader = new MultiReader(readers.toArray(new IndexReader[readers.size()]), true);
96 searcher = new IndexSearcher(multireader);
97 } else {
98 searcher = new IndexSearcher(readers.get(0));
99 }
100 }
101
102 return searcher;
103 }
104
105 /**
106 * does exactly the same as {@link LuceneSearch#getAnalyzer()} but perform
107 * an additional check to assure that all indexes are using the same
108 * analyzer
109 *
110 * @return
111 */
112 @Override
113 public Analyzer getAnalyzer() {
114 SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
115 Analyzer analyzer = null;
116 for(Class<? extends CdmBase> type : directorySelectClasses){
117 Analyzer a = searchFactory.getAnalyzer(type);
118 if(isEqual(analyzer, a)){
119 throw new RuntimeException("The LuceneMultiSearch must only be used on indexes which are using the same Analyzer.");
120 }
121 analyzer = a;
122 }
123 return analyzer;
124 }
125
126 /**
127 * @param analyzer
128 * @param a
129 * @return
130 */
131 private boolean isEqual(Analyzer analyzer, Analyzer a) {
132 // FIXME PatternAnalyzers must be compared by Pattern also other analyzers must be compared by their properties
133 return analyzer != null && !analyzer.getClass().equals(a.getClass());
134 }
135
136 }