X-Git-Url: https://dev.e-taxonomy.eu/gitweb/cdmlib.git/blobdiff_plain/08fcc2cd22a4b168b3e3bd5cbce0d3598972f3ba..52f12e17f79a613e7010b06278d2a3a723cd63eb:/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java diff --git a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java index 8f42471185..c36c1b6b19 100644 --- a/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java +++ b/cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/TaxonServiceImpl.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; @@ -25,7 +26,6 @@ import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; -import org.apache.lucene.search.TopDocs; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -41,14 +41,18 @@ import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableExcepti import eu.etaxonomy.cdm.api.service.pager.Pager; import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl; import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder; +import eu.etaxonomy.cdm.api.service.search.LuceneMultiSearch; import eu.etaxonomy.cdm.api.service.search.LuceneSearch; +import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore; import eu.etaxonomy.cdm.api.service.search.QueryFactory; import eu.etaxonomy.cdm.api.service.search.SearchResult; import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder; +import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge; import eu.etaxonomy.cdm.common.monitor.IProgressMonitor; import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper; import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge; import eu.etaxonomy.cdm.hibernate.search.MultilanguageTextFieldBridge; +import eu.etaxonomy.cdm.model.CdmBaseType; import eu.etaxonomy.cdm.model.common.CdmBase; import eu.etaxonomy.cdm.model.common.IdentifiableEntity; import eu.etaxonomy.cdm.model.common.IdentifiableSource; @@ -57,20 +61,26 @@ import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary; import eu.etaxonomy.cdm.model.common.RelationshipBase; import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction; import eu.etaxonomy.cdm.model.common.UuidAndTitleCache; +import eu.etaxonomy.cdm.model.description.DescriptionBase; import eu.etaxonomy.cdm.model.description.DescriptionElementBase; import eu.etaxonomy.cdm.model.description.Feature; import eu.etaxonomy.cdm.model.description.IIdentificationKey; import eu.etaxonomy.cdm.model.description.PolytomousKeyNode; +import eu.etaxonomy.cdm.model.description.SpecimenDescription; import eu.etaxonomy.cdm.model.description.TaxonDescription; import eu.etaxonomy.cdm.model.description.TaxonInteraction; +import eu.etaxonomy.cdm.model.description.TaxonNameDescription; import eu.etaxonomy.cdm.model.media.Media; import eu.etaxonomy.cdm.model.media.MediaRepresentation; import eu.etaxonomy.cdm.model.media.MediaUtils; +import eu.etaxonomy.cdm.model.molecular.DnaSample; +import eu.etaxonomy.cdm.model.molecular.Sequence; import eu.etaxonomy.cdm.model.name.HomotypicalGroup; import eu.etaxonomy.cdm.model.name.Rank; import eu.etaxonomy.cdm.model.name.TaxonNameBase; import eu.etaxonomy.cdm.model.name.ZoologicalName; import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase; +import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; import eu.etaxonomy.cdm.model.reference.Reference; import eu.etaxonomy.cdm.model.taxon.Classification; import eu.etaxonomy.cdm.model.taxon.Synonym; @@ -81,9 +91,11 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase; import eu.etaxonomy.cdm.model.taxon.TaxonNode; import eu.etaxonomy.cdm.model.taxon.TaxonRelationship; import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType; +import eu.etaxonomy.cdm.persistence.dao.AbstractBeanInitializer; import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao; import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao; import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao; +import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao; import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao; import eu.etaxonomy.cdm.persistence.fetch.CdmFetch; import eu.etaxonomy.cdm.persistence.query.MatchMode; @@ -124,6 +136,12 @@ public class TaxonServiceImpl extends IdentifiableServiceBase searchTaxaByName(String name, Reference sec) { return dao.getTaxaByName(name, sec); } @@ -145,6 +164,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getAllSynonyms(int limit, int start) { return dao.getAllSynonyms(limit, start); } @@ -155,6 +175,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getAllTaxa(int limit, int start) { return dao.getAllTaxa(limit, start); } @@ -165,6 +186,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) { if (cdmFetch == null){ cdmFetch = CdmFetch.NO_FETCH(); @@ -176,6 +198,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List propertyPaths) { return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths); } @@ -183,6 +206,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getAllRelationships(int limit, int start){ return dao.getAllRelationships(limit, start); } @@ -191,6 +215,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getTaxonRelationshipTypeVocabulary() { @@ -207,6 +232,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase findTaxaByName(Class clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) { Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank); @@ -393,6 +422,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listTaxaByName(Class clazz, String uninomial, String infragenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) { Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank); @@ -407,6 +437,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths){ Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo); @@ -420,6 +451,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo); @@ -433,6 +465,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths){ Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom); @@ -446,6 +479,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom); @@ -456,9 +490,86 @@ public class TaxonServiceImpl extends IdentifiableServiceBase(pageNumber, numberOfResults, pageSize, results); } + /** + * @param taxon + * @param includeRelationships + * @param maxDepth + * @param limit + * @param starts + * @param propertyPaths + * @return an List which is not specifically ordered + */ + @Override + public Set listRelatedTaxa(Taxon taxon, Set includeRelationships, Integer maxDepth, + Integer limit, Integer start, List propertyPaths) { + + Set relatedTaxa = collectRelatedTaxa(taxon, includeRelationships, new HashSet(), maxDepth); + relatedTaxa.remove(taxon); + beanInitializer.initializeAll(relatedTaxa, propertyPaths); + return relatedTaxa; + } + + + /** + * recursively collect related taxa for the given taxon . The returned list will also include the + * taxon supplied as parameter. + * + * @param taxon + * @param includeRelationships + * @param taxa + * @param maxDepth can be null for infinite depth + * @return + */ + private Set collectRelatedTaxa(Taxon taxon, Set includeRelationships, Set taxa, Integer maxDepth) { + + if(taxa.isEmpty()) { + taxa.add(taxon); + } + + if(maxDepth != null) { + maxDepth--; + } + if(logger.isDebugEnabled()){ + logger.debug("collecting related taxa for " + taxon + " with maxDepth=" + maxDepth); + } + List taxonRelationships = dao.getTaxonRelationships(taxon, null, null, null, null, null, null); + for (TaxonRelationship taxRel : taxonRelationships) { + + // skip invalid data + if (taxRel.getToTaxon() == null || taxRel.getFromTaxon() == null || taxRel.getType() == null) { + continue; + } + // filter by includeRelationships + for (TaxonRelationshipEdge relationshipEdgeFilter : includeRelationships) { + if ( relationshipEdgeFilter.getTaxonRelationshipType().equals(taxRel.getType()) ) { + if (relationshipEdgeFilter.getDirections().contains(Direction.relatedTo) && !taxa.contains(taxRel.getToTaxon())) { + if(logger.isDebugEnabled()){ + logger.debug(maxDepth + ": " + taxon.getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxRel.getToTaxon().getTitleCache()); + } + taxa.add(taxRel.getToTaxon()); + if(maxDepth == null || maxDepth > 0) { + taxa.addAll(collectRelatedTaxa(taxRel.getToTaxon(), includeRelationships, taxa, maxDepth)); + } + } + if(relationshipEdgeFilter.getDirections().contains(Direction.relatedFrom) && !taxa.contains(taxRel.getFromTaxon())) { + taxa.add(taxRel.getFromTaxon()); + if(logger.isDebugEnabled()){ + logger.debug(maxDepth + ": " +taxRel.getFromTaxon().getTitleCache() + " --[" + taxRel.getType().getLabel() + "]--> " + taxon.getTitleCache() ); + } + if(maxDepth == null || maxDepth > 0) { + taxa.addAll(collectRelatedTaxa(taxRel.getFromTaxon(), includeRelationships, taxa, maxDepth)); + } + } + } + } + } + return taxa; + } + /* (non-Javadoc) * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List) */ + @Override public Pager getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countSynonyms(taxon, type); @@ -473,6 +584,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) { Integer numberOfResults = dao.countSynonyms(synonym, type); @@ -487,6 +599,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List propertyPaths){ Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths); return t.getHomotypicSynonymsByHomotypicGroup(); @@ -495,6 +608,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> getHeterotypicSynonymyGroups(Taxon taxon, List propertyPaths){ Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths); List homotypicalGroups = t.getHeterotypicSynonymyGroups(); @@ -505,6 +619,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator){ List> result = new ArrayList>(); @@ -529,6 +644,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator) { List results = new ArrayList(); @@ -621,6 +737,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){ List medRep = new ArrayList(); taxon = (Taxon)dao.load(taxon.getUuid()); @@ -642,49 +759,126 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listTaxonDescriptionMedia(Taxon taxon, boolean limitToGalleries, List propertyPath){ - - Pager p = - descriptionService.getTaxonDescriptions(taxon, null, null, null, null, propertyPath); + @Override + public List listTaxonDescriptionMedia(Taxon taxon, Set includeRelationships, boolean limitToGalleries, List propertyPath){ + return listMedia(taxon, includeRelationships, limitToGalleries, true, false, false, propertyPath); + } - // pars the media and quality parameters + /* (non-Javadoc) + * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List) + */ + @Override + public List listMedia(Taxon taxon, Set includeRelationships, + Boolean limitToGalleries, Boolean includeTaxonDescriptions, Boolean includeOccurrences, + Boolean includeTaxonNameDescriptions, List propertyPath) { - // collect all media of the given taxon + Set taxa = new HashSet(); List taxonMedia = new ArrayList(); - List taxonGalleryMedia = new ArrayList(); - for(TaxonDescription desc : p.getRecords()){ - if(desc.isImageGallery()){ - for(DescriptionElementBase element : desc.getElements()){ - for(Media media : element.getMedia()){ - taxonGalleryMedia.add(media); + if (limitToGalleries == null) { + limitToGalleries = false; + } + + // --- resolve related taxa + if (includeRelationships != null) { + taxa = listRelatedTaxa(taxon, includeRelationships, null, null, null, null); + } + + taxa.add((Taxon) dao.load(taxon.getUuid())); + + if(includeTaxonDescriptions != null && includeTaxonDescriptions){ + List taxonDescriptions = new ArrayList(); + // --- TaxonDescriptions + for (Taxon t : taxa) { + taxonDescriptions.addAll(descriptionService.listTaxonDescriptions(t, null, null, null, null, propertyPath)); + } + for (TaxonDescription taxonDescription : taxonDescriptions) { + if (!limitToGalleries || taxonDescription.isImageGallery()) { + for (DescriptionElementBase element : taxonDescription.getElements()) { + for (Media media : element.getMedia()) { + taxonMedia.add(media); + } } } - } else if(!limitToGalleries){ - for(DescriptionElementBase element : desc.getElements()){ - for(Media media : element.getMedia()){ - taxonMedia.add(media); + } + } + + if(includeOccurrences != null && includeOccurrences) { + Set specimensOrObservations = new HashSet(); + // --- Specimens + for (Taxon t : taxa) { + specimensOrObservations.addAll(occurrenceDao.listByAssociatedTaxon(null, t, null, null, null, null)); + } + for (SpecimenOrObservationBase occurrence : specimensOrObservations) { + + taxonMedia.addAll(occurrence.getMedia()); + + // SpecimenDescriptions + Set specimenDescriptions = occurrence.getSpecimenDescriptions(); + for (DescriptionBase specimenDescription : specimenDescriptions) { + if (!limitToGalleries || specimenDescription.isImageGallery()) { + Set elements = specimenDescription.getElements(); + for (DescriptionElementBase element : elements) { + for (Media media : element.getMedia()) { + taxonMedia.add(media); + } + } + } + } + + // Collection + if (occurrence instanceof DerivedUnitBase) { + if (((DerivedUnitBase) occurrence).getCollection() != null){ + taxonMedia.addAll(((DerivedUnitBase) occurrence).getCollection().getMedia()); + } + } + + // Chromatograms + if (occurrence instanceof DnaSample) { + Set sequences = ((DnaSample) occurrence).getSequences(); + for (Sequence sequence : sequences) { + taxonMedia.addAll(sequence.getChromatograms()); } } + } + } + if(includeTaxonNameDescriptions != null && includeTaxonNameDescriptions) { + // --- TaxonNameDescription + Set nameDescriptions = new HashSet(); + for (Taxon t : taxa) { + nameDescriptions .addAll(t.getName().getDescriptions()); + } + for(TaxonNameDescription nameDescription: nameDescriptions){ + if (!limitToGalleries || nameDescription.isImageGallery()) { + Set elements = nameDescription.getElements(); + for (DescriptionElementBase element : elements) { + for (Media media : element.getMedia()) { + taxonMedia.add(media); + } + } + } + } } - taxonGalleryMedia.addAll(taxonMedia); - return taxonGalleryMedia; + beanInitializer.initializeAll(taxonMedia, propertyPath); + return taxonMedia; } /* (non-Javadoc) * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set) */ + @Override public List findTaxaByID(Set listOfIDs) { - return this.dao.findById(listOfIDs); + return this.dao.listByIds(listOfIDs, null, null, null, null); } /* (non-Javadoc) * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List propertyPaths) */ + @Override public TaxonBase findTaxonByUuid(UUID uuid, List propertyPaths){ return this.dao.findByUuid(uuid, null ,propertyPaths); } @@ -692,6 +886,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase findIdenticalTaxonNames(List propertyPath) { return this.dao.findIdenticalTaxonNames(propertyPath); } @@ -842,7 +1038,9 @@ public class TaxonServiceImpl extends IdentifiableServiceBase findIdenticalTaxonNameIds(List propertyPath) { return this.dao.findIdenticalNamesNew(propertyPath); @@ -860,6 +1059,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listSynonymRelationships( TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths, Direction direction) { @@ -1128,135 +1331,210 @@ public class TaxonServiceImpl extends IdentifiableServiceBase> findByFullText( Class clazz, String queryString, Classification classification, List languages, boolean highlightFragments, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException { -// // -- set defaults -// Class directorySelectClass = TaxonBase.class; -// if(clazz != null){ -// directorySelectClass = clazz; -// } - return null; + LuceneSearch luceneSearch = prepareFindByFullTextSearch(clazz, queryString, classification, languages, highlightFragments); + + // --- execute search + TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber); + + Map idFieldMap = new HashMap(); + idFieldMap.put(CdmBaseType.TAXON, "id"); + + // --- initialize taxa, thighlight matches .... + ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery()); + List> searchResults = searchResultBuilder.createResultSet( + topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths); + + int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0; + return new DefaultPagerImpl>(pageNumber, totalHits, pageSize, searchResults); } + /** + * @param clazz + * @param queryString + * @param classification + * @param languages + * @param highlightFragments + * @param directorySelectClass + * @return + */ + protected LuceneSearch prepareFindByFullTextSearch(Class clazz, String queryString, Classification classification, List languages, + boolean highlightFragments) { + BooleanQuery finalQuery = new BooleanQuery(); + BooleanQuery textQuery = new BooleanQuery(); + + LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonBase.class); + QueryFactory queryFactory = new QueryFactory(luceneSearch); + + SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", false)}; + luceneSearch.setSortFields(sortFields); + + // ---- search criteria + luceneSearch.setClazz(clazz); + + textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD); + textQuery.add(queryFactory.newDefinedTermQuery("name.rank", queryString, languages), Occur.SHOULD); + + finalQuery.add(textQuery, Occur.MUST); + + if(classification != null){ + finalQuery.add(queryFactory.newEntityIdQuery("taxonNodes.classification.id", classification), Occur.MUST); + } + luceneSearch.setQuery(finalQuery); + + if(highlightFragments){ + luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray()); + } + return luceneSearch; + } + + + /* (non-Javadoc) + * @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) + */ @Override public Pager> findByDescriptionElementFullText( Class clazz, String queryString, Classification classification, List features, List languages, boolean highlightFragments, Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException { - // -- set defaults - Class directorySelectClass = DescriptionElementBase.class; - if(clazz != null){ - directorySelectClass = clazz; - } -// queryString = queryString.toLowerCase(); + LuceneSearch luceneSearch = prepareByDescriptionElementFullTextSearch(clazz, queryString, classification, features, languages, highlightFragments); + + // --- execute search + TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber); + + Map idFieldMap = new HashMap(); + idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id"); + + // --- initialize taxa, highlight matches .... + ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery()); + @SuppressWarnings("rawtypes") + List> searchResults = searchResultBuilder.createResultSet( + topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths); + + int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0; + return new DefaultPagerImpl>(pageNumber, totalHits, pageSize, searchResults); + + } + + + @Override + public Pager> findByEverythingFullText(String queryString, + Classification classification, List languages, boolean highlightFragments, + Integer pageSize, Integer pageNumber, List orderHints, List propertyPaths) throws CorruptIndexException, IOException, ParseException { + + LuceneSearch luceneSearchByDescriptionElement = prepareByDescriptionElementFullTextSearch(null, queryString, classification, null, languages, highlightFragments); + LuceneSearch luceneSearchByTaxonBase = prepareFindByFullTextSearch(null, queryString, classification, languages, highlightFragments); + + LuceneMultiSearch multiSearch = new LuceneMultiSearch(luceneSearchByDescriptionElement, luceneSearchByTaxonBase); + + // --- execute search + TopGroupsWithMaxScore topDocsResultSet = multiSearch.executeSearch(pageSize, pageNumber); + + // --- initialize taxa, highlight matches .... + ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(multiSearch, multiSearch.getQuery()); + + Map idFieldMap = new HashMap(); + idFieldMap.put(CdmBaseType.TAXON, "id"); + idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id"); + + List> searchResults = searchResultBuilder.createResultSet( + topDocsResultSet, multiSearch.getHighlightFields(), dao, idFieldMap, propertyPaths); + + int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupedHitCount : 0; + return new DefaultPagerImpl>(pageNumber, totalHits, pageSize, searchResults); + + } + - StringBuilder luceneQueryTemplate = new StringBuilder(); + /** + * @param clazz + * @param queryString + * @param classification + * @param features + * @param languages + * @param highlightFragments + * @param directorySelectClass + * @return + */ + protected LuceneSearch prepareByDescriptionElementFullTextSearch(Class clazz, String queryString, Classification classification, List features, + List languages, boolean highlightFragments) { BooleanQuery finalQuery = new BooleanQuery(); BooleanQuery textQuery = new BooleanQuery(); - Set freetextFields = new HashSet(); - LuceneSearch luceneSearch = new LuceneSearch(getSession(), directorySelectClass); - QueryFactory queryBuilder = new QueryFactory(luceneSearch); + LuceneSearch luceneSearch = new LuceneSearch(getSession(), DescriptionElementBase.class); + QueryFactory queryFactory = new QueryFactory(luceneSearch); - // ---- search criteria + SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)}; + luceneSearch.setSortFields(sortFields); -// luceneQueryTemplate.append("+("); -// luceneQueryTemplate.append("titleCache:(%1$s) "); - freetextFields.add("titleCache"); - textQuery.add(queryBuilder.newTermQuery("titleCache", queryString), Occur.SHOULD); + // ---- search criteria + luceneSearch.setClazz(clazz); + textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD); // common name - freetextFields.add("name"); - Query nameQuery; if(languages == null || languages.size() == 0){ -// luceneQueryTemplate.append("name:(%1$s) "); - nameQuery = queryBuilder.newTermQuery("name", queryString); + nameQuery = queryFactory.newTermQuery("name", queryString); } else { nameQuery = new BooleanQuery(); BooleanQuery languageSubQuery = new BooleanQuery(); -// luceneQueryTemplate.append("(+name:(%1$s) "); for(Language lang : languages){ -// luceneQueryTemplate.append(" +language.uuid:" + lang.getUuid().toString()); - languageSubQuery.add(queryBuilder.newTermQuery("language.uuid", lang.getUuid().toString()), Occur.SHOULD); + languageSubQuery.add(queryFactory.newTermQuery("language.uuid", lang.getUuid().toString()), Occur.SHOULD); } - ((BooleanQuery) nameQuery).add(queryBuilder.newTermQuery("name", queryString), Occur.MUST); + ((BooleanQuery) nameQuery).add(queryFactory.newTermQuery("name", queryString), Occur.MUST); ((BooleanQuery) nameQuery).add(languageSubQuery, Occur.MUST); -// luceneQueryTemplate.append(")"); } textQuery.add(nameQuery, Occur.SHOULD); // text field from TextData - freetextFields.add("text.ALL"); -// appendLocalizedFieldQuery("text", languages, luceneQueryTemplate).append(" "); - textQuery.add(queryBuilder.newLocalizedTermQuery("text", queryString, languages), Occur.SHOULD); + textQuery.add(queryFactory.newMultilanguageTextQuery("text", queryString, languages), Occur.SHOULD); // --- TermBase fields - by representation ---- // state field from CategoricalData - freetextFields.add("states.state.representation.ALL"); -// appendLocalizedFieldQuery("states.state.representation", languages, luceneQueryTemplate).append(" "); - textQuery.add(queryBuilder.newLocalizedTermQuery("states.state.representation", queryString, languages), Occur.SHOULD); + textQuery.add(queryFactory.newDefinedTermQuery("states.state", queryString, languages), Occur.SHOULD); // state field from CategoricalData - freetextFields.add("states.modifyingText.ALL"); -// appendLocalizedFieldQuery("states.modifyingText", languages, luceneQueryTemplate).append(" "); - textQuery.add(queryBuilder.newLocalizedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD); -// luceneQueryTemplate.append(") "); + textQuery.add(queryFactory.newDefinedTermQuery("states.modifyingText", queryString, languages), Occur.SHOULD); + + // area field from Distribution + textQuery.add(queryFactory.newDefinedTermQuery("area", queryString, languages), Occur.SHOULD); + + // status field from Distribution + textQuery.add(queryFactory.newDefinedTermQuery("status", queryString, languages), Occur.SHOULD); finalQuery.add(textQuery, Occur.MUST); // --- classification ---- if(classification != null){ -// luceneQueryTemplate.append("+inDescription.taxon.taxonNodes.classification.id:").append(PaddedIntegerBridge.paddInteger(classification.getId())).append(" "); - finalQuery.add(queryBuilder.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST); + finalQuery.add(queryFactory.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification), Occur.MUST); } // --- IdentifieableEntity fields - by uuid if(features != null && features.size() > 0 ){ - finalQuery.add(queryBuilder.newEntityUuidQuery("feature.uuid", features), Occur.MUST); -// luceneQueryTemplate.append("+feature.uuid:("); -// for(Feature feature : features){ -// luceneQueryTemplate.append(feature.getUuid()).append(" "); -// } -// luceneQueryTemplate.append(") "); + finalQuery.add(queryFactory.newEntityUuidQuery("feature.uuid", features), Occur.MUST); } // the description must be associated with a taxon -// luceneQueryTemplate.append("+inDescription.taxon.id:[ " + PaddedIntegerBridge.paddInteger(0) + " TO " + PaddedIntegerBridge.paddInteger(Integer.MAX_VALUE) + "] "); - //luceneQueryTemplate.append("-inDescription.taxon.id:" + PaddedIntegerBridge.NULL_STRING); - finalQuery.add(queryBuilder.newIdNotNullQuery("inDescription.taxon.id"), Occur.MUST); - -// String luceneQueryStr = String.format(luceneQueryTemplate.toString(), queryString); - - // --- sort fields - SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("inDescription.taxon.titleCache__sort", false)}; - - // ---- execute criteria + finalQuery.add(queryFactory.newIsNotNullQuery("inDescription.taxon.id"), Occur.MUST); + luceneSearch.setQuery(finalQuery); -// Query luceneQuery = luceneSearch.parse(luceneQueryStr); - TopDocs topDocsResultSet = luceneSearch.executeSearch(finalQuery, clazz, pageSize, pageNumber, sortFields); - - String[] highlightFields = null; if(highlightFragments){ - highlightFields = freetextFields.toArray(new String[freetextFields.size()]); + luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray()); } - - // initialize taxa, thighlight matches .... - ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, finalQuery); - List> searchResults = searchResultBuilder.createResultSet( - topDocsResultSet, highlightFields, dao, "inDescription.taxon.id", propertyPaths); - - return new DefaultPagerImpl>(pageNumber, searchResults.size(), pageSize, searchResults); - + return luceneSearch; } /** @@ -1287,6 +1565,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase createInferredSynonyms(Taxon taxon, Classification classification, SynonymRelationshipType type, boolean doWithMisappliedNames){ List inferredSynonyms = new ArrayList(); List inferredSynonymsToBeRemoved = new ArrayList(); @@ -1316,7 +1595,7 @@ public class TaxonServiceImpl extends IdentifiableServiceBase createAllInferredSynonyms(Taxon taxon, Classification tree, boolean doWithMisappliedNames){ List inferredSynonyms = new ArrayList(); @@ -1913,6 +2193,39 @@ public class TaxonServiceImpl extends IdentifiableServiceBase listClassifications(TaxonBase taxonBase, Integer limit, Integer start, List propertyPaths) { + + // TODO quickly implemented, create according dao !!!! + Set nodes = new HashSet(); + Set classifications = new HashSet(); + List list = new ArrayList(); + + if (taxonBase == null) { + return list; + } + + taxonBase = load(taxonBase.getUuid()); + + if (taxonBase instanceof Taxon) { + nodes.addAll(((Taxon)taxonBase).getTaxonNodes()); + } else { + for (Taxon taxon : ((Synonym)taxonBase).getAcceptedTaxa() ) { + nodes.addAll(taxon.getTaxonNodes()); + } + } + for (TaxonNode node : nodes) { + classifications.add(node.getClassification()); + } + list.addAll(classifications); + return list; + } + + +