test for TaxonService.findByFullText() successful
authorAndreas Kohlbecker <a.kohlbecker@bgbm.org>
Tue, 18 Sep 2012 21:15:54 +0000 (21:15 +0000)
committerAndreas Kohlbecker <a.kohlbecker@bgbm.org>
Tue, 18 Sep 2012 21:15:54 +0000 (21:15 +0000)
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/taxon/TaxonBase.java
cdmlib-persistence/src/main/resources/eu/etaxonomy/cdm/persistence.xml
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/search/QueryFactory.java
cdmlib-services/src/main/resources/eu/etaxonomy/cdm/services.xml
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/TaxonServiceSearchTest.java

index 35a22183b5729511739f1e47c9325170f3198661..4e381b49b5e95fa2ab2e22cf64940cd966eb74b3 100644 (file)
@@ -30,6 +30,7 @@ import org.hibernate.annotations.CascadeType;
 import org.hibernate.annotations.Index;
 import org.hibernate.annotations.Table;
 import org.hibernate.envers.Audited;
+import org.hibernate.search.annotations.Indexed;
 import org.hibernate.search.annotations.IndexedEmbedded;
 
 import org.springframework.security.access.prepost.PreFilter;
index 7c808b2787d1e40ed861d0f742567e9dddcf81a3..6d623bce27b40285534f77c56ea63f55aef7379b 100644 (file)
@@ -2,8 +2,8 @@
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans
-    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+       xsi:schemaLocation="
+    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
index beb58134b1fb3c581363cba49f01a47b690821bf..6a9c83da6d78b7a175cd59ddb6e953706e053ec6 100644 (file)
@@ -63,6 +63,7 @@ import eu.etaxonomy.cdm.model.description.IIdentificationKey;
 import eu.etaxonomy.cdm.model.description.PolytomousKeyNode;\r
 import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
 import eu.etaxonomy.cdm.model.description.TaxonInteraction;\r
+import eu.etaxonomy.cdm.model.description.TextData;\r
 import eu.etaxonomy.cdm.model.media.Media;\r
 import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.media.MediaUtils;\r
@@ -1128,21 +1129,64 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         return dao.getUuidAndTitleCacheSynonym();\r
     }\r
 \r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+     */\r
     @Override\r
     public Pager<SearchResult<TaxonBase>> findByFullText(\r
             Class<? extends TaxonBase> clazz, String queryString,\r
             Classification classification, List<Language> languages,\r
             boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
 \r
-//        // -- set defaults\r
-//        Class<? extends TaxonBase> directorySelectClass = TaxonBase.class;\r
-//        if(clazz != null){\r
-//            directorySelectClass = clazz;\r
-//        }\r
-        return null;\r
+        // -- set defaults\r
+        // abstract base classes cannot be used as directorySelectClass but any subclass will do!\r
+        Class<? extends TaxonBase> directorySelectClass = Taxon.class;\r
+        if(clazz != null){\r
+            if(clazz.equals(TaxonBase.class)){\r
+                clazz = null;\r
+            } else {\r
+                directorySelectClass = clazz;\r
+            }\r
+        }\r
+\r
+        BooleanQuery finalQuery = new BooleanQuery();\r
+        BooleanQuery textQuery = new BooleanQuery();\r
 \r
+        LuceneSearch luceneSearch = new LuceneSearch(getSession(), directorySelectClass);\r
+        QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
+\r
+        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", false)};\r
+\r
+        // ---- search criteria\r
+        textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
+        textQuery.add(queryFactory.newDefinedTermBaseQuery("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
+        }\r
+\r
+        String[] highlightFields = null;\r
+        if(highlightFragments){\r
+            highlightFields = queryFactory.getTextFieldNamesAsArray();\r
+        }\r
+\r
+        // --- execute search\r
+        TopDocs topDocsResultSet = luceneSearch.executeSearch(finalQuery, clazz, pageSize, pageNumber, sortFields);\r
+\r
+        // ---  initialize taxa, thighlight matches ....\r
+        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, finalQuery);\r
+        List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
+                topDocsResultSet, highlightFields, dao, "taxon.id", propertyPaths);\r
+\r
+        return new DefaultPagerImpl<SearchResult<TaxonBase>>(pageNumber, searchResults.size(), pageSize, searchResults);\r
     }\r
 \r
+\r
+    /* (non-Javadoc)\r
+     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByDescriptionElementFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)\r
+     */\r
     @Override\r
     public Pager<SearchResult<TaxonBase>> findByDescriptionElementFullText(\r
             Class<? extends DescriptionElementBase> clazz, String queryString,\r
@@ -1150,18 +1194,24 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
             boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {\r
 \r
         // -- set defaults\r
-        Class<? extends DescriptionElementBase> directorySelectClass = DescriptionElementBase.class;\r
+        // abstract base classes cannot be used as directorySelectClass but any subclass will do!\r
+        Class<? extends DescriptionElementBase> directorySelectClass = TextData.class;\r
         if(clazz != null){\r
-            directorySelectClass = clazz;\r
+             if(clazz.equals(TaxonBase.class)){\r
+                 clazz = null;\r
+             } else {\r
+                 directorySelectClass = clazz;\r
+             }\r
         }\r
 \r
-\r
         BooleanQuery finalQuery = new BooleanQuery();\r
         BooleanQuery textQuery = new BooleanQuery();\r
 \r
         LuceneSearch luceneSearch = new LuceneSearch(getSession(), directorySelectClass);\r
         QueryFactory queryFactory = new QueryFactory(luceneSearch);\r
 \r
+        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)};\r
+\r
         // ---- search criteria\r
         textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);\r
 \r
@@ -1206,16 +1256,16 @@ public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDa
         // the description must be associated with a taxon\r
         finalQuery.add(queryFactory.newIdNotNullQuery("inDescription.taxon.id"), Occur.MUST);\r
 \r
-        SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)};\r
-\r
-        TopDocs topDocsResultSet = luceneSearch.executeSearch(finalQuery, clazz, pageSize, pageNumber, sortFields);\r
 \r
         String[] highlightFields = null;\r
         if(highlightFragments){\r
-            highlightFields = queryFactory.getTextFieldNames().toArray(new String[queryFactory.getTextFieldNames().size()]);\r
+            highlightFields = queryFactory.getTextFieldNamesAsArray();\r
         }\r
 \r
-        // initialize taxa, thighlight matches ....\r
+        // --- execute search\r
+        TopDocs topDocsResultSet = luceneSearch.executeSearch(finalQuery, clazz, pageSize, pageNumber, sortFields);\r
+\r
+        // --- initialize taxa, thighlight matches ....\r
         ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, finalQuery);\r
         List<SearchResult<TaxonBase>> searchResults = searchResultBuilder.createResultSet(\r
                 topDocsResultSet, highlightFields, dao, "inDescription.taxon.id", propertyPaths);\r
index a2481f2c726ac44fe68495fbb5d586f81da43992..57b8b230b949612402b177f660b138bdc5861d39 100644 (file)
@@ -47,6 +47,10 @@ public class QueryFactory {
         return textFieldNames;
     }
 
+    public String[] getTextFieldNamesAsArray() {
+        return textFieldNames.toArray(new String[textFieldNames.size()]);
+    }
+
 
     public QueryFactory(LuceneSearch luceneSearch){
         this.luceneSearch = luceneSearch;
@@ -96,15 +100,31 @@ public class QueryFactory {
      */
     public Query newLocalizedTermQuery(String name, String queryString, List<Language> languages) {
 
+        BooleanQuery localizedTermQuery = new BooleanQuery();
+        localizedTermQuery.add(newTermQuery(name + ".label", queryString), Occur.SHOULD);
         if(languages == null || languages.size() == 0){
-            return newTermQuery(name + ".ALL", queryString);
+            localizedTermQuery.add(newTermQuery(name + ".ALL", queryString), Occur.SHOULD);
         } else {
-            BooleanQuery localizedTermQuery = new BooleanQuery();
             for(Language lang : languages){
                 localizedTermQuery.add(newTermQuery(name + "." + lang.getUuid().toString(), queryString), Occur.SHOULD);
             }
-            return localizedTermQuery;
         }
+        return localizedTermQuery;
+    }
+
+    /**
+     * convenience method for localized searches on {@link DefinedTermBase}
+     * instances, it adds the field name suffix "representations" to the
+     * <code>name</code> parameter and calls
+     * {@link #newLocalizedTermQuery(String, String, List)}
+     *
+     * @param name
+     * @param queryString
+     * @param languages
+     * @return
+     */
+    public Query newDefinedTermBaseQuery(String name, String queryString, List<Language> languages) {
+        return newLocalizedTermQuery(name + ".representations", queryString, languages);
     }
 
     /**
index 6c0a05cd55b7b29906b7592dcc7b959216939bb3..85509065b199da5787cdffa2258eabbcc64d7728 100644 (file)
@@ -3,9 +3,9 @@
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
   xmlns:context="http://www.springframework.org/schema/context"\r
   xsi:schemaLocation="\r
-    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd\r
-    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"\r
-    >\r
+    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\r
+    ">\r
 \r
     <import resource="classpath:/eu/etaxonomy/cdm/persistence.xml"/>\r
 \r
index a079c6e60121e4e17118ac8b5b87e11d105ef0b3..a8639f1042b5dac8cd815f92ec567db3d97a740c 100644 (file)
@@ -509,6 +509,35 @@ public class TaxonServiceSearchTest extends CdmTransactionalIntegrationTest {
         Assert.assertTrue("first fragments should contains serch term", fragments[0].contains("<B>Pflanzenart</B> <B>aus</B> <B>der</B> <B>Gattung</B> <B>der</B> <B>Tannen</B>"));\r
     }\r
 \r
+\r
+    @Test\r
+    @DataSet\r
+    public final void testFindByFullText() throws CorruptIndexException, IOException, ParseException {\r
+\r
+        refreshLuceneIndex();\r
+\r
+        Pager<SearchResult<TaxonBase>> pager;\r
+//        pager = taxonService.findByFullText(null, "Abies", null, null, true, null, null, null, null); // --> 7\r
+//        Assert.assertEquals("Expecting 7 entities", Integer.valueOf(7), pager.getCount());\r
+\r
+        pager = taxonService.findByFullText(Taxon.class, "Abies", null, null, true, null, null, null, null); // --> 6\r
+        Assert.assertEquals("Expecting 6 entities", Integer.valueOf(6), pager.getCount());\r
+\r
+        pager = taxonService.findByFullText(Synonym.class, "Abies", null, null, true, null, null, null, null); // --> 1\r
+        Assert.assertEquals("Expecting 1 entity", Integer.valueOf(1), pager.getCount());\r
+\r
+        pager = taxonService.findByFullText(TaxonBase.class, "sec*", null, null, true, null, null, null, null); // --> 7\r
+        Assert.assertEquals("Expecting 7 entities", Integer.valueOf(7), pager.getCount());\r
+\r
+        pager = taxonService.findByFullText(null, "genus", null, null, true, null, null, null, null); // --> 1\r
+        Assert.assertEquals("Expecting 1 entity", Integer.valueOf(1), pager.getCount());\r
+\r
+        pager = taxonService.findByFullText(Taxon.class, "subalpina", null, null, true, null, null, null, null); // --> 0\r
+        Assert.assertEquals("Expecting 0 entities", Integer.valueOf(0), pager.getCount());\r
+\r
+        // synonym in classification ???\r
+    }\r
+\r
     /**\r
      *\r
      */\r