merge hibernate4 migration branch into trunk
[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 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 */
49 public LuceneMultiSearch(LuceneSearch... luceneSearch) {
50 session = luceneSearch[0].session;
51
52 BooleanQuery query = new BooleanQuery();
53
54 Set<String> highlightFields = new HashSet<String>();
55
56 for(LuceneSearch search : luceneSearch){
57 this.directorySelectClasses.add(search.getDirectorySelectClass());
58 query.add(search.getQuery(), Occur.SHOULD);
59 highlightFields.addAll(Arrays.asList(search.getHighlightFields()));
60 }
61
62 this.highlightFields = highlightFields.toArray(new String[highlightFields.size()]);
63 this.query = query;
64
65 }
66
67 /**
68 * @return
69 */
70 @Override
71 public IndexSearcher getSearcher() {
72
73 if(searcher == null){
74
75 SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
76 List<IndexReader> readers = new ArrayList<IndexReader>();
77 for(Class<? extends CdmBase> type : directorySelectClasses){
78 //OLD
79 // DirectoryProvider[] directoryProviders = searchFactory.getDirectoryProviders(type);
80 // logger.info(directoryProviders[0].getDirectory().toString());
81
82 // ReaderProvider readerProvider = searchFactory.getReaderProvider();
83 IndexReaderAccessor ira = searchFactory.getIndexReaderAccessor();
84 IndexReader reader = ira.open(type);
85 // readers.add(readerProvider.openReader(directoryProviders[0]));
86 readers.add(reader);
87 }
88 if(readers.size() > 1){
89 MultiReader multireader = new MultiReader(readers.toArray(new IndexReader[readers.size()]), true);
90 searcher = new IndexSearcher(multireader);
91 } else {
92 searcher = new IndexSearcher(readers.get(0));
93 }
94 }
95
96 return searcher;
97 }
98
99 /**
100 * does exactly the same as {@link LuceneSearch#getAnalyzer()} but perform
101 * an additional check to assure that all indexes are using the same
102 * analyzer
103 *
104 * @return
105 */
106 @Override
107 public Analyzer getAnalyzer() {
108 SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
109 Analyzer analyzer = null;
110 for(Class<? extends CdmBase> type : directorySelectClasses){
111 Analyzer a = searchFactory.getAnalyzer(type);
112 if(isEqual(analyzer, a)){
113 throw new RuntimeException("The LuceneMultiSearch must only be used on indexes which are using the same Analyzer.");
114 }
115 analyzer = a;
116 }
117 return analyzer;
118 }
119
120 /**
121 * @param analyzer
122 * @param a
123 * @return
124 */
125 private boolean isEqual(Analyzer analyzer, Analyzer a) {
126 // FIXME PatternAnalyzers must be compared by Pattern also other analyzers must be compared by their properties
127 return analyzer != null && !analyzer.getClass().equals(a.getClass());
128 }
129
130 }