refactoring for a lucene cross index search
authorAndreas Kohlbecker <a.kohlbecker@bgbm.org>
Wed, 25 Sep 2013 09:06:56 +0000 (09:06 +0000)
committerAndreas Kohlbecker <a.kohlbecker@bgbm.org>
Wed, 25 Sep 2013 09:06:56 +0000 (09:06 +0000)
.gitattributes
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/NameServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/OccurrenceServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ILuceneIndexToolProvider.java [new file with mode: 0644]
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneIndexToolProviderImpl.java [new file with mode: 0644]
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneMultiSearch.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneSearch.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/QueryFactory.java

index b12ff1382a9a6991d5992e77bae3244c8899508c..1861093a78eab7337aa64acd040cae41c6b59cbb 100644 (file)
@@ -2117,7 +2117,9 @@ cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/pager/impl/StringLabe
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/CdmMassIndexer.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/DocumentSearchResult.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ICdmMassIndexer.java -text
+cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ILuceneIndexToolProvider.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ISearchResultBuilder.java -text
+cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneIndexToolProviderImpl.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneMultiSearch.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneMultiSearchException.java -text
 cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneSearch.java -text
index ca590b0fe9f804ef8268d1bb89a43f6a5b3d6736..8c908fe8c0cfbb34aae66d2d907b3f13579ddfeb 100644 (file)
@@ -41,6 +41,7 @@ import eu.etaxonomy.cdm.api.service.pager.Pager;
 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
 import eu.etaxonomy.cdm.api.service.search.DocumentSearchResult;\r
+import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;\r
 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;\r
 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;\r
 import eu.etaxonomy.cdm.api.service.search.QueryFactory;\r
@@ -106,6 +107,8 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
     private IHomotypicalGroupDao homotypicalGroupDao;\r
     @Autowired\r
     private ICdmGenericDao genericDao;\r
+    @Autowired\r
+    private ILuceneIndexToolProvider luceneIndexToolProvider;\r
 \r
     /**\r
      * Constructor\r
@@ -557,96 +560,96 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
 \r
 \r
     protected LuceneSearch prepareFindByFuzzyNameSearch(Class<? extends CdmBase> clazz,\r
-               NonViralName nvn,\r
-               float accuracy,\r
-               int maxNoOfResults,\r
-               List<Language> languages,\r
-               boolean highlightFragments) {\r
-       String similarity = Float.toString(accuracy);\r
-       String searchSuffix = "~" + similarity;\r
+            NonViralName nvn,\r
+            float accuracy,\r
+            int maxNoOfResults,\r
+            List<Language> languages,\r
+            boolean highlightFragments) {\r
+        String similarity = Float.toString(accuracy);\r
+        String searchSuffix = "~" + similarity;\r
 \r
 \r
-       BooleanQuery finalQuery = new BooleanQuery(false);\r
-       BooleanQuery textQuery = new BooleanQuery(false);\r
+        BooleanQuery finalQuery = new BooleanQuery(false);\r
+        BooleanQuery textQuery = new BooleanQuery(false);\r
 \r
-       LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);\r
-       QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);\r
+        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);\r
 \r
 //     SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
 //     luceneSearch.setSortFields(sortFields);\r
 \r
-       // ---- search criteria\r
-       luceneSearch.setClazz(clazz);\r
+        // ---- search criteria\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
 \r
-       FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());\r
-       if(nvn.getGenusOrUninomial() != null && !nvn.getGenusOrUninomial().equals("")) {\r
-               fltq.addTerms(nvn.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy, 3);\r
-       } else {\r
-               //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
-               textQuery.add(queryFactory.newTermQuery("genusOrUninomial", "_null_", false), Occur.MUST);\r
-       }\r
+        FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());\r
+        if(nvn.getGenusOrUninomial() != null && !nvn.getGenusOrUninomial().equals("")) {\r
+            fltq.addTerms(nvn.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy, 3);\r
+        } else {\r
+            //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
+            textQuery.add(queryFactory.newTermQuery("genusOrUninomial", "_null_", false), Occur.MUST);\r
+        }\r
 \r
-       if(nvn.getInfraGenericEpithet() != null && !nvn.getInfraGenericEpithet().equals("")){\r
-               fltq.addTerms(nvn.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy, 3);\r
-       } else {\r
-               //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
-               textQuery.add(queryFactory.newTermQuery("infraGenericEpithet", "_null_", false), Occur.MUST);\r
-       }\r
+        if(nvn.getInfraGenericEpithet() != null && !nvn.getInfraGenericEpithet().equals("")){\r
+            fltq.addTerms(nvn.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy, 3);\r
+        } else {\r
+            //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
+            textQuery.add(queryFactory.newTermQuery("infraGenericEpithet", "_null_", false), Occur.MUST);\r
+        }\r
 \r
-       if(nvn.getSpecificEpithet() != null && !nvn.getSpecificEpithet().equals("")){\r
-               fltq.addTerms(nvn.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy, 3);\r
-       } else {\r
-               //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
-               textQuery.add(queryFactory.newTermQuery("specificEpithet", "_null_", false), Occur.MUST);\r
-       }\r
+        if(nvn.getSpecificEpithet() != null && !nvn.getSpecificEpithet().equals("")){\r
+            fltq.addTerms(nvn.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy, 3);\r
+        } else {\r
+            //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
+            textQuery.add(queryFactory.newTermQuery("specificEpithet", "_null_", false), Occur.MUST);\r
+        }\r
 \r
-       if(nvn.getInfraSpecificEpithet() != null && !nvn.getInfraSpecificEpithet().equals("")){\r
-               fltq.addTerms(nvn.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy, 3);\r
-       } else {\r
-               //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
-               textQuery.add(queryFactory.newTermQuery("infraSpecificEpithet", "_null_", false), Occur.MUST);\r
-       }\r
+        if(nvn.getInfraSpecificEpithet() != null && !nvn.getInfraSpecificEpithet().equals("")){\r
+            fltq.addTerms(nvn.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy, 3);\r
+        } else {\r
+            //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
+            textQuery.add(queryFactory.newTermQuery("infraSpecificEpithet", "_null_", false), Occur.MUST);\r
+        }\r
 \r
-       if(nvn.getAuthorshipCache() != null && !nvn.getAuthorshipCache().equals("")){\r
-               fltq.addTerms(nvn.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy, 3);\r
-       } else {\r
-               //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
-       }\r
+        if(nvn.getAuthorshipCache() != null && !nvn.getAuthorshipCache().equals("")){\r
+            fltq.addTerms(nvn.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy, 3);\r
+        } else {\r
+            //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);\r
+        }\r
 \r
-       textQuery.add(fltq, Occur.MUST);\r
+        textQuery.add(fltq, Occur.MUST);\r
 \r
-       finalQuery.add(textQuery, Occur.MUST);\r
+        finalQuery.add(textQuery, Occur.MUST);\r
 \r
-       luceneSearch.setQuery(finalQuery);\r
+        luceneSearch.setQuery(finalQuery);\r
 \r
-       if(highlightFragments){\r
-               luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
-       }\r
-       return luceneSearch;\r
+        if(highlightFragments){\r
+            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+        }\r
+        return luceneSearch;\r
     }\r
 \r
     protected LuceneSearch prepareFindByFuzzyNameCacheSearch(Class<? extends CdmBase> clazz,\r
-               String name,\r
-               float accuracy,\r
-               int maxNoOfResults,\r
-               List<Language> languages,\r
+            String name,\r
+            float accuracy,\r
+            int maxNoOfResults,\r
+            List<Language> languages,\r
             boolean highlightFragments) {\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);\r
+        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);\r
 \r
 //     SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
 //     luceneSearch.setSortFields(sortFields);\r
 \r
         // ---- search criteria\r
-        luceneSearch.setClazz(clazz);\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
         FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());\r
 \r
         fltq.addTerms(name, "nameCache", accuracy, 3);\r
 \r
-       BooleanQuery finalQuery = new BooleanQuery(false);\r
+         BooleanQuery finalQuery = new BooleanQuery(false);\r
 \r
-       finalQuery.add(fltq, Occur.MUST);\r
+         finalQuery.add(fltq, Occur.MUST);\r
 \r
         luceneSearch.setQuery(finalQuery);\r
 \r
@@ -657,28 +660,28 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
     }\r
 \r
     protected LuceneSearch prepareFindByExactNameSearch(Class<? extends CdmBase> clazz,\r
-               String name,\r
-               boolean wildcard,\r
-               List<Language> languages,\r
+            String name,\r
+            boolean wildcard,\r
+            List<Language> languages,\r
             boolean highlightFragments) {\r
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);\r
+        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);\r
 \r
 //     SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
 //     luceneSearch.setSortFields(sortFields);\r
 \r
         // ---- search criteria\r
-        luceneSearch.setClazz(clazz);\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
 \r
         if(name != null && !name.equals("")) {\r
-               if(wildcard) {\r
-                       textQuery.add(new WildcardQuery(new Term("nameCache", name + "*")), Occur.MUST);\r
-               } else {\r
-                       textQuery.add(queryFactory.newTermQuery("nameCache", name, false), Occur.MUST);\r
-               }\r
+            if(wildcard) {\r
+                textQuery.add(new WildcardQuery(new Term("nameCache", name + "*")), Occur.MUST);\r
+            } else {\r
+                textQuery.add(queryFactory.newTermQuery("nameCache", name, false), Occur.MUST);\r
+            }\r
         }\r
 \r
         luceneSearch.setQuery(textQuery);\r
@@ -698,13 +701,13 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
             List<String> propertyPaths,\r
             int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {\r
 \r
-       logger.info("Name to fuzzy search for : " + name);\r
-       // parse the input name\r
-       NonViralNameParserImpl parser = new NonViralNameParserImpl();\r
-       NonViralName nvn = parser.parseFullName(name);\r
-       if(name != null && !name.equals("") && nvn == null) {\r
-               throw new ParseException("Could not parse name " + name);\r
-       }\r
+        logger.info("Name to fuzzy search for : " + name);\r
+        // parse the input name\r
+        NonViralNameParserImpl parser = new NonViralNameParserImpl();\r
+        NonViralName nvn = parser.parseFullName(name);\r
+        if(name != null && !name.equals("") && nvn == null) {\r
+            throw new ParseException("Could not parse name " + name);\r
+        }\r
         LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, maxNoOfResults, languages, highlightFragments);\r
 \r
         // --- execute search\r
@@ -733,13 +736,13 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
             boolean highlightFragments,\r
             int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {\r
 \r
-       logger.info("Name to fuzzy search for : " + name);\r
-       // parse the input name\r
-       NonViralNameParserImpl parser = new NonViralNameParserImpl();\r
-       NonViralName nvn = parser.parseFullName(name);\r
-       if(name != null && !name.equals("") && nvn == null) {\r
-               throw new ParseException("Could not parse name " + name);\r
-       }\r
+        logger.info("Name to fuzzy search for : " + name);\r
+        // parse the input name\r
+        NonViralNameParserImpl parser = new NonViralNameParserImpl();\r
+        NonViralName nvn = parser.parseFullName(name);\r
+        if(name != null && !name.equals("") && nvn == null) {\r
+            throw new ParseException("Could not parse name " + name);\r
+        }\r
         LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, maxNoOfResults, languages, highlightFragments);\r
 \r
         // --- execute search\r
@@ -759,12 +762,12 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
     @Override\r
     public List<DocumentSearchResult> findByFuzzyNameCacheSearch(\r
             String name,\r
-               float accuracy,\r
+            float accuracy,\r
             List<Language> languages,\r
             boolean highlightFragments,\r
             int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {\r
 \r
-       logger.info("Name to fuzzy search for : " + name);\r
+        logger.info("Name to fuzzy search for : " + name);\r
 \r
         LuceneSearch luceneSearch = prepareFindByFuzzyNameCacheSearch(null, name, accuracy, maxNoOfResults, languages, highlightFragments);\r
 \r
@@ -789,9 +792,9 @@ public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxo
             boolean highlightFragments,\r
             int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {\r
 \r
-       logger.info("Name to exact search for : " + name);\r
+        logger.info("Name to exact search for : " + name);\r
 \r
-       LuceneSearch luceneSearch = prepareFindByExactNameSearch(null, name, wildcard, languages, highlightFragments);\r
+        LuceneSearch luceneSearch = prepareFindByExactNameSearch(null, name, wildcard, languages, highlightFragments);\r
 \r
         // --- execute search\r
 \r
index 9115ac49116f1a901988626bf85794a6703aae2c..8e452898502d70754bfffd3e633ba2089a73e9be 100644 (file)
@@ -35,6 +35,7 @@ import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;\r
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
+import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;\r
 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;\r
 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;\r
 import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;\r
@@ -92,6 +93,8 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
     @Autowired\r
     private ITaxonDao taxonDao;\r
 \r
+    @Autowired\r
+    private ILuceneIndexToolProvider luceneIndexToolProvider;\r
 \r
 \r
     public OccurrenceServiceImpl() {\r
@@ -338,11 +341,11 @@ public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObs
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), FieldObservation.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldObservation.class);\r
+        QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldObservation.class);\r
 \r
         // --- criteria\r
-        luceneSearch.setClazz(clazz);\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
         if(queryString != null){\r
             textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
             finalQuery.add(textQuery, Occur.MUST);\r
index b8972ddfd612c207c6724263cac617854e4d91c4..b6fb31f7dec023d64eafc4b272b397f1cd96f076 100644 (file)
@@ -25,7 +25,6 @@ import org.apache.lucene.index.CorruptIndexException;
 import org.apache.lucene.queryParser.ParseException;\r
 import org.apache.lucene.search.BooleanClause.Occur;\r
 import org.apache.lucene.search.BooleanQuery;\r
-import org.apache.lucene.search.IndexSearcher;\r
 import org.apache.lucene.search.Query;\r
 import org.apache.lucene.search.QueryWrapperFilter;\r
 import org.apache.lucene.search.SortField;\r
@@ -42,6 +41,7 @@ import eu.etaxonomy.cdm.api.service.exception.HomotypicalGroupChangeException;
 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;\r
 import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;\r
+import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;\r
 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;\r
 import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearch;\r
 import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearchException;\r
@@ -150,7 +150,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
     @Autowired\r
     private AbstractBeanInitializer beanInitializer;\r
 \r
-    private static IndexSearcher taxonRelationshipSearcher;\r
+    @Autowired\r
+    private ILuceneIndexToolProvider luceneIndexToolProvider;\r
+\r
 \r
     /**\r
      * Constructor\r
@@ -1409,27 +1411,27 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, TaxonBase.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, TaxonBase.class);\r
+        QueryFactory taxonBaseQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonBase.class);\r
 \r
         SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
         luceneSearch.setSortFields(sortFields);\r
 \r
         // ---- search criteria\r
-        luceneSearch.setClazz(clazz);\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
 \r
-        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
-        textQuery.add(queryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(taxonBaseQueryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+        textQuery.add(taxonBaseQueryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD);\r
 \r
         finalQuery.add(textQuery, Occur.MUST);\r
 \r
         if(classification != null){\r
-            finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
+            finalQuery.add(taxonBaseQueryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
         }\r
         luceneSearch.setQuery(finalQuery);\r
 \r
         if(highlightFragments){\r
-            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+            luceneSearch.setHighlightFields(taxonBaseQueryFactory.getTextFieldNamesAsArray());\r
         }\r
         return luceneSearch;\r
     }\r
@@ -1475,13 +1477,13 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         BooleanQuery finalQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonBase.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonBase.class);\r
+        QueryFactory taxonBaseQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonBase.class);\r
 \r
         BooleanQuery joinFromQuery = new BooleanQuery();\r
-        joinFromQuery.add(queryFactory.newTermQuery(queryTermField, queryString), Occur.MUST);\r
-        joinFromQuery.add(queryFactory.newEntityIdQuery("type.id", edge.getTaxonRelationshipType()), Occur.MUST);\r
-        Query joinQuery = queryFactory.newJoinQuery(fromField, toField, joinFromQuery, TaxonRelationship.class);\r
+        joinFromQuery.add(taxonBaseQueryFactory.newTermQuery(queryTermField, queryString), Occur.MUST);\r
+        joinFromQuery.add(taxonBaseQueryFactory.newEntityIdQuery("type.id", edge.getTaxonRelationshipType()), Occur.MUST);\r
+        Query joinQuery = taxonBaseQueryFactory.newJoinQuery(fromField, toField, joinFromQuery, TaxonRelationship.class);\r
 \r
         SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};\r
         luceneSearch.setSortFields(sortFields);\r
@@ -1489,12 +1491,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         finalQuery.add(joinQuery, Occur.MUST);\r
 \r
         if(classification != null){\r
-            finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
+            finalQuery.add(taxonBaseQueryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
         }\r
         luceneSearch.setQuery(finalQuery);\r
 \r
         if(highlightFragments){\r
-            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+            luceneSearch.setHighlightFields(taxonBaseQueryFactory.getTextFieldNamesAsArray());\r
         }\r
         return luceneSearch;\r
     }\r
@@ -1557,7 +1559,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             idFieldMap.put(CdmBaseType.TAXON, "id");\r
         }\r
 \r
-        LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneSearches.toArray(new LuceneSearch[luceneSearches.size()]));\r
+        LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneIndexToolProvider, luceneSearches.toArray(new LuceneSearch[luceneSearches.size()]));\r
 \r
         if(namedAreas != null && namedAreas.size() > 0){\r
             //  - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html\r
@@ -1572,11 +1574,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             //  - http://www.infoq.com/articles/LuceneSpatialSupport\r
             //  - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html\r
 \r
+            QueryFactory distributionQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(Distribution.class);\r
 \r
-            // TODO can't we use a static QueryFactory field?\r
-            QueryFactory queryFactory = new QueryFactory(luceneSearches.get(0));\r
-\r
-            Query taxonAreaJoinQuery = createByDistributionJoinQuery(namedAreaList, distributionStatusList, queryFactory);\r
+            Query taxonAreaJoinQuery = createByDistributionJoinQuery(namedAreaList, distributionStatusList, distributionQueryFactory);\r
             multiSearch.setFilter(new QueryWrapperFilter(taxonAreaJoinQuery));\r
         }\r
 \r
@@ -1639,19 +1639,21 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
 \r
         BooleanQuery finalQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, Taxon.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, Taxon.class);\r
+\r
+        // FIXME is this query factory using the wrong type?\r
+        QueryFactory taxonQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(Taxon.class);\r
 \r
         SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};\r
         luceneSearch.setSortFields(sortFields);\r
 \r
 \r
-        Query byAreaQuery = createByDistributionJoinQuery(namedAreaList, distributionStatusList, queryFactory);\r
+        Query byAreaQuery = createByDistributionJoinQuery(namedAreaList, distributionStatusList, taxonQueryFactory);\r
 \r
         finalQuery.add(byAreaQuery, Occur.MUST);\r
 \r
         if(classification != null){\r
-            finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
+            finalQuery.add(taxonQueryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST);\r
         }\r
 \r
         logger.info("prepareByAreaSearch() query: " + finalQuery.toString());\r
@@ -1700,7 +1702,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments);\r
         LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments);\r
 \r
-        LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneSearchByDescriptionElement, luceneSearchByTaxonBase);\r
+        LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneIndexToolProvider, luceneSearchByDescriptionElement, luceneSearchByTaxonBase);\r
 \r
         // --- execute search\r
         TopGroupsWithMaxScore topDocsResultSet = multiSearch.executeSearch(pageSize, pageNumber);\r
@@ -1737,68 +1739,68 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
-        LuceneSearch luceneSearch = new LuceneSearch(getSession(), GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, DescriptionElementBase.class);\r
-        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+        LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, GroupByTaxonClassBridge.GROUPBY_TAXON_FIELD, DescriptionElementBase.class);\r
+        QueryFactory descriptionElementQueryFactory = luceneIndexToolProvider.newQueryFactoryFor(DescriptionElementBase.class);\r
 \r
         SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", SortField.STRING, false)};\r
         luceneSearch.setSortFields(sortFields);\r
 \r
         // ---- search criteria\r
-        luceneSearch.setClazz(clazz);\r
-        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+        luceneSearch.setCdmTypRestriction(clazz);\r
+        textQuery.add(descriptionElementQueryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
 \r
         // common name\r
         Query nameQuery;\r
         if(languages == null || languages.size() == 0){\r
-            nameQuery = queryFactory.newTermQuery("name", queryString);\r
+            nameQuery = descriptionElementQueryFactory.newTermQuery("name", queryString);\r
         } else {\r
             nameQuery = new BooleanQuery();\r
             BooleanQuery languageSubQuery = new BooleanQuery();\r
             for(Language lang : languages){\r
-                languageSubQuery.add(queryFactory.newTermQuery("language.uuid",  lang.getUuid().toString(), false), Occur.SHOULD);\r
+                languageSubQuery.add(descriptionElementQueryFactory.newTermQuery("language.uuid",  lang.getUuid().toString(), false), Occur.SHOULD);\r
             }\r
-            ((BooleanQuery) nameQuery).add(queryFactory.newTermQuery("name", queryString), Occur.MUST);\r
+            ((BooleanQuery) nameQuery).add(descriptionElementQueryFactory.newTermQuery("name", queryString), Occur.MUST);\r
             ((BooleanQuery) nameQuery).add(languageSubQuery, Occur.MUST);\r
         }\r
         textQuery.add(nameQuery, Occur.SHOULD);\r
 \r
 \r
         // text field from TextData\r
-        textQuery.add(queryFactory.newMultilanguageTextQuery("text", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(descriptionElementQueryFactory.newMultilanguageTextQuery("text", queryString, languages), Occur.SHOULD);\r
 \r
         // --- TermBase fields - by representation ----\r
         // state field from CategoricalData\r
-        textQuery.add(queryFactory.newDefinedTermQuery("states.state", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(descriptionElementQueryFactory.newDefinedTermQuery("states.state", queryString, languages), Occur.SHOULD);\r
 \r
         // state field from CategoricalData\r
-        textQuery.add(queryFactory.newDefinedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(descriptionElementQueryFactory.newDefinedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD);\r
 \r
         // area field from Distribution\r
-        textQuery.add(queryFactory.newDefinedTermQuery("area", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(descriptionElementQueryFactory.newDefinedTermQuery("area", queryString, languages), Occur.SHOULD);\r
 \r
         // status field from Distribution\r
-        textQuery.add(queryFactory.newDefinedTermQuery("status", queryString, languages), Occur.SHOULD);\r
+        textQuery.add(descriptionElementQueryFactory.newDefinedTermQuery("status", queryString, languages), Occur.SHOULD);\r
 \r
         finalQuery.add(textQuery, Occur.MUST);\r
         // --- classification ----\r
 \r
         if(classification != null){\r
-            finalQuery.add(queryFactory.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST);\r
+            finalQuery.add(descriptionElementQueryFactory.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST);\r
         }\r
 \r
         // --- IdentifieableEntity fields - by uuid\r
         if(features != null && features.size() > 0 ){\r
-            finalQuery.add(queryFactory.newEntityUuidsQuery("feature.uuid", features), Occur.MUST);\r
+            finalQuery.add(descriptionElementQueryFactory.newEntityUuidsQuery("feature.uuid", features), Occur.MUST);\r
         }\r
 \r
         // the description must be associated with a taxon\r
-        finalQuery.add(queryFactory.newIsNotNullQuery("inDescription.taxon.id"), Occur.MUST);\r
+        finalQuery.add(descriptionElementQueryFactory.newIsNotNullQuery("inDescription.taxon.id"), Occur.MUST);\r
 \r
         logger.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery.toString());\r
         luceneSearch.setQuery(finalQuery);\r
 \r
         if(highlightFragments){\r
-            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());\r
+            luceneSearch.setHighlightFields(descriptionElementQueryFactory.getTextFieldNamesAsArray());\r
         }\r
         return luceneSearch;\r
     }\r
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ILuceneIndexToolProvider.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/ILuceneIndexToolProvider.java
new file mode 100644 (file)
index 0000000..a699d0f
--- /dev/null
@@ -0,0 +1,66 @@
+// $Id$
+/**
+ * Copyright (C) 2013 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
+package eu.etaxonomy.cdm.api.service.search;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.queryParser.QueryParser;
+import org.hibernate.search.indexes.IndexReaderAccessor;
+
+import eu.etaxonomy.cdm.model.common.CdmBase;
+
+/**
+ * @author a.kohlbecker
+ * @date Sep 18, 2013
+ *
+ */
+public interface ILuceneIndexToolProvider {
+
+    /**
+     * @return the IndexReader suitable for the lucene index of the given
+     *         <code>clazz</code>
+     */
+    public abstract IndexReader getIndexReaderFor(Class<? extends CdmBase> clazz);
+
+    /**
+     * Either creates a new QueryParser or returns the QueryParser which has
+     * been created before for the specified class. The QueryParsers per CdmBase
+     * type are cached in a Map.
+     *
+     * @return the QueryParser suitable for the lucene index of the given
+     *         <code>clazz</code>
+     */
+    public abstract QueryParser getQueryParserFor(Class<? extends CdmBase> clazz);
+
+    /**
+     * <b>WARING</b> The implementation of this method might return an Analyzer
+     * which is not suitable for all fields of the lucene document. This method
+     * internally uses the simplified method from {@link {
+     * @link org.hibernate.search.SearchFactory#getAnalyzer(Class)}
+     *
+     * @return the Analyzer suitable for the lucene index of the given
+     *         <code>clazz</code>
+     */
+    public abstract Analyzer getAnalyzerFor(Class<? extends CdmBase> clazz);
+
+    /**
+     * Creates new QueryFactory for the specified Cdm type.
+     *
+     * @return A new QueryFactory suitable for the lucene index of the given
+     *         <code>clazz</code>
+     */
+    public abstract QueryFactory newQueryFactoryFor(Class<? extends CdmBase> clazz);
+
+    /**
+     * @return the IndexReaderAccessor from the SearchFactory
+     */
+    public abstract IndexReaderAccessor getIndexReaderAccessor();
+
+}
\ No newline at end of file
diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneIndexToolProviderImpl.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/LuceneIndexToolProviderImpl.java
new file mode 100644 (file)
index 0000000..3fb815d
--- /dev/null
@@ -0,0 +1,139 @@
+// $Id$
+/**
+ * Copyright (C) 2013 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
+package eu.etaxonomy.cdm.api.service.search;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.queryParser.QueryParser;
+import org.hibernate.SessionFactory;
+import org.hibernate.search.Search;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.indexes.IndexReaderAccessor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import eu.etaxonomy.cdm.config.Configuration;
+import eu.etaxonomy.cdm.model.common.CdmBase;
+import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
+import eu.etaxonomy.cdm.model.description.TextData;
+import eu.etaxonomy.cdm.model.name.NonViralName;
+import eu.etaxonomy.cdm.model.name.TaxonNameBase;
+import eu.etaxonomy.cdm.model.taxon.Taxon;
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;
+
+/**
+ * @author a.kohlbecker
+ * @date Sep 18, 2013
+ *
+ */
+@Component
+public class LuceneIndexToolProviderImpl implements ILuceneIndexToolProvider {
+
+    private final static String DEFAULT_QURERY_FIELD_NAME = "titleCache";
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    private final Map<Class<? extends CdmBase>, QueryParser> queryParsers = new HashMap<Class<? extends CdmBase>, QueryParser>();
+
+    /**
+     * @param sessionfactory
+     * @return
+     */
+    private SearchFactory getCurrentSearchFactory() {
+        return Search.getFullTextSession(sessionFactory.getCurrentSession()).getSearchFactory();
+    }
+
+
+    /**
+     * TODO the abstract base class DescriptionElementBase can not be used, so
+     * we are using an arbitrary subclass to find the DirectoryProvider, future
+     * versions of hibernate search my allow using abstract base classes see
+     * {@link http://stackoverflow.com/questions/492184/how-do-you-find-all-subclasses-of-a-given-class-in-java}
+     *
+     * @param type must not be null
+     * @return
+     */
+    protected Class<? extends CdmBase> pushAbstractBaseTypeDown(Class<? extends CdmBase> type) {
+        if(type == null) {
+            throw new NullPointerException("parameter type must not be null");
+        }
+        if (type.equals(DescriptionElementBase.class)) {
+            return TextData.class;
+        }
+        if (type.equals(TaxonBase.class)) {
+            return Taxon.class;
+        }
+        if (type.equals(TaxonNameBase.class)) {
+            return NonViralName.class;
+        }
+        return type;
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider#getIndexReaderFor(java.lang.Class)
+     */
+    @Override
+    public IndexReader getIndexReaderFor(Class<? extends CdmBase> clazz) {
+        IndexReader reader = getCurrentSearchFactory().getIndexReaderAccessor().open(pushAbstractBaseTypeDown(clazz));
+        return reader;
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider#getQueryParserFor(java.lang.Class)
+     */
+    @Override
+    public QueryParser getQueryParserFor(Class<? extends CdmBase> clazz) {
+        if(!queryParsers.containsKey(clazz)){
+            Analyzer analyzer = getAnalyzerFor(clazz);
+            QueryParser parser = new QueryParser(Configuration.luceneVersion, DEFAULT_QURERY_FIELD_NAME, analyzer);
+            queryParsers.put(clazz, parser);
+        }
+        return queryParsers.get(clazz);
+    }
+
+    /**
+     * <b>WARING</b> This method might return an Analyzer
+     * which is not suitable for all fields of the lucene document. This method
+     * internally uses the simplified method from {@link {
+     * @link org.hibernate.search.SearchFactory#getAnalyzer(Class)}
+     *
+     * TODO implement method which allows to retrieve the correct Analyzer
+     * per document field, this method will have another signature.
+     *
+     * @return the Analyzer suitable for the lucene index of the given
+     *         <code>clazz</code>
+     */
+    @Override
+    public Analyzer getAnalyzerFor(Class<? extends CdmBase> clazz) {
+        Analyzer analyzer = getCurrentSearchFactory().getAnalyzer(pushAbstractBaseTypeDown(clazz));
+        return analyzer;
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider#getQueryFactoryFor(java.lang.Class)
+     */
+    @Override
+    public QueryFactory newQueryFactoryFor(Class<? extends CdmBase> clazz){
+        return new QueryFactory(this, pushAbstractBaseTypeDown(clazz));
+    }
+
+    /* (non-Javadoc)
+     * @see eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider#getIndexReaderAccessor()
+     */
+    @Override
+    public IndexReaderAccessor getIndexReaderAccessor(){
+        return getCurrentSearchFactory().getIndexReaderAccessor();
+    }
+
+}
\ No newline at end of file
index 6bf69dae907bb3d7202c6a9c099484be623b07aa..63e1187d27319c406bacf7ebc3f1f8fa1cb82f31 100644 (file)
@@ -23,8 +23,6 @@ import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.SortField;
-import org.hibernate.search.Search;
-import org.hibernate.search.SearchFactory;
 import org.hibernate.search.indexes.IndexReaderAccessor;
 
 import eu.etaxonomy.cdm.model.common.CdmBase;
@@ -48,9 +46,9 @@ public class LuceneMultiSearch extends LuceneSearch {
      * @param luceneSearch the searches to execute together as a union like search
      * @throws Exception
      */
-    public LuceneMultiSearch(LuceneSearch... luceneSearch) throws LuceneMultiSearchException {
+    public LuceneMultiSearch(ILuceneIndexToolProvider toolProvider, LuceneSearch... luceneSearch) throws LuceneMultiSearchException {
 
-        session = luceneSearch[0].session;
+        this.toolProvider = toolProvider;
         groupByField = null; //reset
         BooleanQuery query = new BooleanQuery();
 
@@ -66,13 +64,13 @@ public class LuceneMultiSearch extends LuceneSearch {
             highlightFields.addAll(Arrays.asList(search.getHighlightFields()));
 
             // set the class for each of the sub searches
-            if(search.clazz != null){
-                if(clazz != null && !clazz.equals(search.clazz)){
+            if(search.cdmTypRestriction != null){
+                if(cdmTypRestriction != null && !cdmTypRestriction.equals(search.cdmTypRestriction)){
                     throw new LuceneMultiSearchException(
                             "LuceneMultiSearch can only handle once class restriction, but multiple given: " +
-                            getClazz() + ", " + search.getClazz());
+                            getCdmTypRestriction() + ", " + search.getCdmTypRestriction());
                 }
-                setClazz(search.getClazz());
+                setCdmTypRestriction(search.getCdmTypRestriction());
             }
 
             // set the groupByField for each of the sub searches
@@ -106,8 +104,6 @@ public class LuceneMultiSearch extends LuceneSearch {
     public IndexSearcher getSearcher() {
 
         if(searcher == null){
-
-            SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
             List<IndexReader> readers = new ArrayList<IndexReader>();
             for(Class<? extends CdmBase> type : directorySelectClasses){
                    //OLD
@@ -115,7 +111,7 @@ public class LuceneMultiSearch extends LuceneSearch {
 //                logger.info(directoryProviders[0].getDirectory().toString());
 
 //                ReaderProvider readerProvider = searchFactory.getReaderProvider();
-                IndexReaderAccessor ira = searchFactory.getIndexReaderAccessor();
+                IndexReaderAccessor ira = toolProvider.getIndexReaderAccessor();
                 IndexReader reader = ira.open(type);
 //             readers.add(readerProvider.openReader(directoryProviders[0]));
                 readers.add(reader);
@@ -140,10 +136,9 @@ public class LuceneMultiSearch extends LuceneSearch {
      */
     @Override
     public Analyzer getAnalyzer() {
-        SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
         Analyzer analyzer = null;
         for(Class<? extends CdmBase> type : directorySelectClasses){
-            Analyzer a = searchFactory.getAnalyzer(type);
+            Analyzer a = toolProvider.getAnalyzerFor(type);
             if(isEqual(analyzer, a)){
                 throw new RuntimeException("The LuceneMultiSearch must only be used on indexes which are using the same Analyzer.");
             }
index a083460972d7578e509fd3b46d23bed527fffd92..2ca3715d2c83584490ff5a16bb7e5bbfd97a3a0f 100644 (file)
@@ -14,10 +14,8 @@ import java.util.Collection;
 
 import org.apache.log4j.Logger;
 import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.queryParser.ParseException;
-import org.apache.lucene.queryParser.QueryParser;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.Filter;
@@ -34,12 +32,8 @@ import org.apache.lucene.search.grouping.TermAllGroupsCollector;
 import org.apache.lucene.search.grouping.TermFirstPassGroupingCollector;
 import org.apache.lucene.search.grouping.TermSecondPassGroupingCollector;
 import org.apache.lucene.search.grouping.TopGroups;
-import org.hibernate.Session;
 import org.hibernate.search.ProjectionConstants;
-import org.hibernate.search.Search;
-import org.hibernate.search.SearchFactory;
 
-import eu.etaxonomy.cdm.config.Configuration;
 import eu.etaxonomy.cdm.model.common.CdmBase;
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
 import eu.etaxonomy.cdm.model.description.TextData;
@@ -62,7 +56,7 @@ public class LuceneSearch {
 
     public static final Logger logger = Logger.getLogger(LuceneSearch.class);
 
-    protected Session session;
+    protected ILuceneIndexToolProvider toolProvider;
 
     protected IndexSearcher searcher;
 
@@ -79,11 +73,11 @@ public class LuceneSearch {
     /**
      * classFilter
      */
-    protected Class<? extends CdmBase> clazz;
+    protected Class<? extends CdmBase> cdmTypRestriction;
 
 
-    public Class<? extends CdmBase> getClazz() {
-        return clazz;
+    public Class<? extends CdmBase> getCdmTypRestriction() {
+        return cdmTypRestriction;
     }
 
     /**
@@ -105,7 +99,7 @@ public class LuceneSearch {
      * <code>directorySelectClass</code> the Class is set to <code>null</code>
      * @param clazz
      */
-    public void setClazz(Class<? extends CdmBase> clazz) {
+    public void setCdmTypRestriction(Class<? extends CdmBase> clazz) {
 
         /*
          * NOTE:
@@ -115,7 +109,7 @@ public class LuceneSearch {
         if(clazz != null && clazz.equals(directorySelectClass)){
             clazz = null;
         }
-        this.clazz = clazz;
+        this.cdmTypRestriction = clazz;
     }
 
     /**
@@ -144,40 +138,41 @@ public class LuceneSearch {
     /**
      * @param session
      */
-    public LuceneSearch(Session session, Class<? extends CdmBase> directorySelectClass) {
-         this.session = session;
+    public LuceneSearch(ILuceneIndexToolProvider toolProvider, Class<? extends CdmBase> directorySelectClass) {
+         this.toolProvider = toolProvider;
          this.directorySelectClass = directorySelectClass;
     }
 
     /**
      * @param session
      */
-    public LuceneSearch(Session session, String groupByField, Class<? extends CdmBase> directorySelectClass) {
-         this.session = session;
-         this.directorySelectClass = directorySelectClass;
-         this.groupByField = groupByField;
+    public LuceneSearch(ILuceneIndexToolProvider toolProvider, String groupByField, Class<? extends CdmBase> directorySelectClass) {
+        this.toolProvider = toolProvider;
+        this.directorySelectClass = directorySelectClass;
+        this.groupByField = groupByField;
     }
 
     /**
      * TODO the abstract base class DescriptionElementBase can not be used, so
-     * we are using an arbitraty subclass to find the DirectoryProvider, future
+     * we are using an arbitrary subclass to find the DirectoryProvider, future
      * versions of hibernate search my allow using abstract base classes see
      * {@link http://stackoverflow.com/questions/492184/how-do-you-find-all-subclasses-of-a-given-class-in-java}
      *
      * @param type must not be null
      * @return
      */
-    protected Class<? extends CdmBase> pushAbstractBaseTypeDown(Class<? extends CdmBase> type) {
+    private Class<? extends CdmBase> pushAbstractBaseTypeDown(Class<? extends CdmBase> type) {
+        Class<? extends CdmBase> returnType = type;
         if (type.equals(DescriptionElementBase.class)) {
-            type = TextData.class;
+            returnType = TextData.class;
         }
         if (type.equals(TaxonBase.class)) {
-            type = Taxon.class;
+            returnType = Taxon.class;
         }
         if (type.equals(TaxonNameBase.class)) {
-            type = NonViralName.class;
+            returnType = NonViralName.class;
         }
-        return type;
+        return returnType;
     }
 
     protected LuceneSearch() {
@@ -189,51 +184,26 @@ public class LuceneSearch {
      */
     public IndexSearcher getSearcher() {
         if(searcher == null){
-            searcher = new IndexSearcher(getIndexReader());
+            searcher = new IndexSearcher(toolProvider.getIndexReaderFor(directorySelectClass));
             searcher.setDefaultFieldSortScoring(true, true);
         }
         return searcher;
     }
 
     /**
-     * @return
-     */
-    public IndexReader getIndexReader() {
-        SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
-        IndexReader reader = searchFactory.getIndexReaderAccessor().open(getDirectorySelectClass());
-        return reader;
-    }
-
-    /**
-     * @return
-     */
-    public IndexReader getIndexReaderFor(Class<? extends CdmBase> clazz) {
-        SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
-        IndexReader reader = searchFactory.getIndexReaderAccessor().open(pushAbstractBaseTypeDown(clazz));
-        return reader;
-    }
-
-    /**
-     * @return
-     */
-    public QueryParser getQueryParser() {
-        Analyzer analyzer = getAnalyzer();
-        QueryParser parser = new QueryParser(Configuration.luceneVersion,  "titleCache", analyzer);
-        return parser;
-    }
-
-    /**
-     * @return
+     * Convenience method which delegated the call to the available
+     * {@link ILuceneIndexToolProvider#getAnalyzerFor(Class)} method.
+     *
+     * @return the Analyzer suitable for the <code>directorySelectClass</code>
+     * of the LuceneSearch
      */
     public Analyzer getAnalyzer() {
-        SearchFactory searchFactory = Search.getFullTextSession(session).getSearchFactory();
-        Analyzer analyzer = searchFactory.getAnalyzer(getDirectorySelectClass());
-        return analyzer;
+        return toolProvider.getAnalyzerFor(directorySelectClass);
     }
 
     /**
      * @param luceneQueryString
-     * @param clazz the type as additional filter criterion
+     * @param cdmTypRestriction the type as additional filter criterion
      * @param pageSize if the page size is null or in an invalid range it will be set to MAX_HITS_ALLOWED
      * @param pageNumber a 0-based index of the page to return, will default to 0 if null or negative.
      * @return
@@ -255,7 +225,7 @@ public class LuceneSearch {
      */
     public Query parse(String luceneQueryString) throws ParseException {
         logger.debug("luceneQueryString to be parsed: " + luceneQueryString);
-        Query luceneQuery = getQueryParser().parse(luceneQueryString);
+        Query luceneQuery = toolProvider.getQueryParserFor(directorySelectClass).parse(luceneQueryString);
         return luceneQuery;
     }
 
@@ -345,15 +315,15 @@ public class LuceneSearch {
     }
 
     /**
-     * @param clazz
+     * @param cdmTypRestriction
      */
     protected Query expandQuery() {
         Query fullQuery;
-        if(clazz != null){
+        if(cdmTypRestriction != null){
             BooleanQuery filteredQuery = new BooleanQuery();
             BooleanQuery classFilter = new BooleanQuery();
 
-            Term t = new Term(ProjectionConstants.OBJECT_CLASS, clazz.getName());
+            Term t = new Term(ProjectionConstants.OBJECT_CLASS, cdmTypRestriction.getName());
             TermQuery termQuery = new TermQuery(t);
 
             classFilter.setBoost(0);
index 6fa781512a81325c8e10dc05a3bc606160235ef6..5053d79b4ec3149399979c2c0077979dcc107ceb 100644 (file)
@@ -45,6 +45,21 @@ import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
 import eu.etaxonomy.cdm.model.common.Language;
 
 /**
+ * QueryFactory creates queries for a specific lucene index that means queries
+ * specific to the various CDM base types. Therefore the QueryFactory hold a
+ * reference to a {@link LuceneSearch} instance which has been created for a
+ * CDM base type.<br>
+ * The field names used in queries created on free text fields are remembered
+ * and can be accessed by {@link #getTextFieldNames()} or {@link #getTextFieldNamesAsArray()}.
+ * This is useful for highlighting the matches with {@link LuceneSearch#setHighlightFields(String[])}
+ * <p>
+ * The index specific methods from {@link LuceneSearch} which are
+ * used by QueryFactory directly or indirectly are:
+ * <ul>
+ * <li>{@link LuceneSearch#getAnalyzer()}</li>
+ * </ul>
+ *
+ *
  * @author a.kohlbecker
  * @date Sep 14, 2012
  *
@@ -53,13 +68,13 @@ public class QueryFactory {
 
     public static final Logger logger = Logger.getLogger(QueryFactory.class);
 
-    private final LuceneSearch luceneSearch;
+    protected ILuceneIndexToolProvider toolProvider;
 
     Set<String> textFieldNames = new HashSet<String>();
 
     Map<Class<? extends CdmBase>, IndexSearcher> indexSearcherMap = new HashMap<Class<? extends CdmBase>, IndexSearcher>();
 
-    private BooleanQuery finalQuery;
+    private final Class<? extends CdmBase> cdmBaseType;
 
     public Set<String> getTextFieldNames() {
         return textFieldNames;
@@ -69,9 +84,9 @@ public class QueryFactory {
         return textFieldNames.toArray(new String[textFieldNames.size()]);
     }
 
-
-    public QueryFactory(LuceneSearch luceneSearch){
-        this.luceneSearch = luceneSearch;
+    public QueryFactory(ILuceneIndexToolProvider toolProvider, Class<? extends CdmBase> cdmBaseType){
+        this.cdmBaseType = cdmBaseType;
+        this.toolProvider = toolProvider;
     }
 
     /**
@@ -96,7 +111,7 @@ public class QueryFactory {
             // in order to support the full query syntax we must use the parser
             // here
             try {
-                return luceneSearch.parse(luceneQueryString);
+                return toolProvider.getQueryParserFor(cdmBaseType).parse(luceneQueryString);
             } catch (ParseException e) {
                 logger.error(e);
             }
@@ -219,7 +234,7 @@ public class QueryFactory {
      * @param entity
      * @return
      */
-    private Query newEntityUuidQuery(String uuidFieldName, IdentifiableEntity entity) {
+    public Query newEntityUuidQuery(String uuidFieldName, IdentifiableEntity entity) {
         return newTermQuery(uuidFieldName, entity.getUuid().toString(), false);
     }
 
@@ -261,18 +276,6 @@ public class QueryFactory {
         return uuidInQuery;
     }
 
-    public void setFinalQuery(BooleanQuery finalQuery) {
-        this.finalQuery = finalQuery;
-    }
-
-    public BooleanQuery getFinalQuery(){
-        return finalQuery;
-    }
-
-    public LuceneSearch getLuceneSearch() {
-        return luceneSearch;
-    }
-
 
     /**
      * Returns a Lucene Query which rely on double numeric range query
@@ -341,7 +344,7 @@ public class QueryFactory {
     private IndexSearcher indexSearcherFor(Class<? extends CdmBase> clazz) {
         if(indexSearcherMap.get(clazz) == null){
 
-            IndexReader indexReader = luceneSearch.getIndexReaderFor(clazz);
+            IndexReader indexReader = toolProvider.getIndexReaderFor(clazz);
             IndexSearcher searcher = new IndexSearcher(indexReader);
             searcher.setDefaultFieldSortScoring(true, true);
             indexSearcherMap.put(clazz, searcher);