From dd7b59644ba0f95bb2bb2c4a0ba70dccfd847332 Mon Sep 17 00:00:00 2001 From: buczekp <buczekp> Date: Tue, 22 Mar 2011 09:32:48 +0000 Subject: [PATCH] [LMS-2148] fixed search with container; added search with children SVN: 20434 --- ...riaToDetailedSearchCriteriaTranslator.java | 6 +- .../business/DetailedSearchManager.java | 123 +++++++++++++----- .../bo/samplelister/ISampleLister.java | 6 +- .../bo/samplelister/SampleLister.java | 4 +- .../search/detailed/IndexFieldNameHelper.java | 7 +- .../shared/api/v1/dto/SearchSubCriteria.java | 5 + .../api/v1/dto/SearchableEntityKind.java | 2 +- .../basic/dto/AssociatedEntityKind.java | 4 +- .../openbis/generic/shared/dto/SamplePE.java | 4 +- .../api/v1/GeneralInformationServiceTest.java | 40 ++++++ .../api/v1/GeneralInformationServiceTest.java | 31 +++++ 11 files changed, 187 insertions(+), 45 deletions(-) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java index 7023576eb94..5cdde53f652 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java @@ -59,6 +59,7 @@ class SearchCriteriaToDetailedSearchCriteriaTranslator translators.put(SearchableEntityKind.EXPERIMENT, new ExperimentAttributeTranslator()); translators.put(SearchableEntityKind.SAMPLE, new SampleAttributeTranslator()); translators.put(SearchableEntityKind.SAMPLE_PARENT, new SampleAttributeTranslator()); + translators.put(SearchableEntityKind.SAMPLE_CHILD, new SampleAttributeTranslator()); translators.put(SearchableEntityKind.SAMPLE_CONTAINER, new SampleAttributeTranslator()); } @@ -74,7 +75,8 @@ class SearchCriteriaToDetailedSearchCriteriaTranslator attribute, entityKind)); } - private static AssociatedEntityKind convertToAssociatedEntityKind(SearchableEntityKind entityKind) + private static AssociatedEntityKind convertToAssociatedEntityKind( + SearchableEntityKind entityKind) { switch (entityKind) { @@ -86,6 +88,8 @@ class SearchCriteriaToDetailedSearchCriteriaTranslator return AssociatedEntityKind.SAMPLE_CONTAINER; case SAMPLE_PARENT: return AssociatedEntityKind.SAMPLE_PARENT; + case SAMPLE_CHILD: + return AssociatedEntityKind.SAMPLE_CHILD; } return null; // can't happen } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/DetailedSearchManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/DetailedSearchManager.java index f2bca9d4b3a..f3f69c066e5 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/DetailedSearchManager.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/DetailedSearchManager.java @@ -59,60 +59,110 @@ public class DetailedSearchManager List<DetailedSearchSubCriteria> subCriterias) throws DataAccessException { final DetailedSearchCriteria parentCriteria = new DetailedSearchCriteria(); + final DetailedSearchCriteria childCriteria = new DetailedSearchCriteria(); final List<DetailedSearchSubCriteria> otherSubCriterias = new ArrayList<DetailedSearchSubCriteria>(); - groupSampleSubCriteria(subCriterias, parentCriteria, otherSubCriterias); + groupSampleSubCriteria(subCriterias, parentCriteria, childCriteria, otherSubCriterias); final List<Long> mainSampleIds = findSampleIds(criteria, otherSubCriterias); - final Set<Long> filteredSampleIds; - if (parentCriteria.isEmpty()) - { - filteredSampleIds = new HashSet<Long>(mainSampleIds); - } else + final Set<Long> filteredSampleIds = new HashSet<Long>(); + if (false == parentCriteria.isEmpty()) { final List<Long> parentSampleIds = findSampleIds(parentCriteria, Collections.<DetailedSearchSubCriteria> emptyList()); - - filteredSampleIds = new HashSet<Long>(); - if (mainSampleIds.size() > parentSampleIds.size()) { - // search for connections - Map<Long, Set<Long>> parentToChildIds = - sampleLister.listChildrenIds(parentSampleIds); - for (Set<Long> childrenIds : parentToChildIds.values()) - { - filteredSampleIds.addAll(childrenIds); - } - // filter main parents - filteredSampleIds.retainAll(mainSampleIds); + listParentsChildrenAndFilterChildren(mainSampleIds, parentSampleIds, + filteredSampleIds); + } else + { + listChildrensParentsAndFilterChildren(mainSampleIds, parentSampleIds, + filteredSampleIds); + } + } else if (false == childCriteria.isEmpty()) + { + final List<Long> childSampleIds = + findSampleIds(childCriteria, + Collections.<DetailedSearchSubCriteria> emptyList()); + if (mainSampleIds.size() > childSampleIds.size()) + { + listChildrensParentsAndFilterParents(childSampleIds, mainSampleIds, + filteredSampleIds); } else { - // search for connections - Map<Long, Set<Long>> childToParentIds = sampleLister.listParentIds(mainSampleIds); - - // filter main parents - for (Entry<Long, Set<Long>> entry : childToParentIds.entrySet()) - { - Long childId = entry.getKey(); - Set<Long> parentIds = entry.getValue(); - parentIds.retainAll(parentSampleIds); - if (parentIds.isEmpty() == false) - { - filteredSampleIds.add(childId); - } - } + listParentsChildrenAndFilterParents(childSampleIds, mainSampleIds, + filteredSampleIds); } + + } else + { + filteredSampleIds.addAll(mainSampleIds); } return sampleLister.list(new ListOrSearchSampleCriteria(filteredSampleIds)); } + private void listChildrensParentsAndFilterChildren(final List<Long> allChildrenIds, + final List<Long> allParentIds, final Set<Long> filteredChildrenIds) + { + Map<Long, Set<Long>> childToParentIds = sampleLister.getChildToParentsIdsMap(allChildrenIds); + for (Entry<Long, Set<Long>> entry : childToParentIds.entrySet()) + { + Long childId = entry.getKey(); + Set<Long> parentIds = entry.getValue(); + parentIds.retainAll(allParentIds); + if (parentIds.isEmpty() == false) + { + filteredChildrenIds.add(childId); + } + } + } + + private void listParentsChildrenAndFilterParents(final List<Long> allChildrenIds, + final List<Long> allParentIds, final Set<Long> filteredParentIds) + { + Map<Long, Set<Long>> parentToChildIds = sampleLister.getParentToChildrenIdsMap(allParentIds); + for (Entry<Long, Set<Long>> entry : parentToChildIds.entrySet()) + { + Long parentId = entry.getKey(); + Set<Long> childIds = entry.getValue(); + childIds.retainAll(allChildrenIds); + if (childIds.isEmpty() == false) + { + filteredParentIds.add(parentId); + } + } + } + + private void listParentsChildrenAndFilterChildren(final List<Long> allChildrenIds, + final List<Long> allParentIds, final Set<Long> filteredChildrenIds) + { + Map<Long, Set<Long>> parentToChildIds = sampleLister.getParentToChildrenIdsMap(allParentIds); + for (Set<Long> childrenIds : parentToChildIds.values()) + { + filteredChildrenIds.addAll(childrenIds); + } + filteredChildrenIds.retainAll(allChildrenIds); + } + + private void listChildrensParentsAndFilterParents(final List<Long> allChildrenIds, + final List<Long> allParentIds, final Set<Long> filteredParentsIds) + { + Map<Long, Set<Long>> childToParentIds = sampleLister.getChildToParentsIdsMap(allChildrenIds); + for (Set<Long> parentIds : childToParentIds.values()) + { + filteredParentsIds.addAll(parentIds); + } + filteredParentsIds.retainAll(allParentIds); + } + private void groupSampleSubCriteria(List<DetailedSearchSubCriteria> allSubCriterias, - DetailedSearchCriteria parentCriteria, List<DetailedSearchSubCriteria> otherSubCriterias) + DetailedSearchCriteria parentCriteria, DetailedSearchCriteria childCriteria, + List<DetailedSearchSubCriteria> otherSubCriterias) { parentCriteria.setCriteria(new ArrayList<DetailedSearchCriterion>()); + childCriteria.setCriteria(new ArrayList<DetailedSearchCriterion>()); for (DetailedSearchSubCriteria subCriteria : allSubCriterias) { switch (subCriteria.getTargetEntityKind()) @@ -124,6 +174,13 @@ public class DetailedSearchManager parentCriteria.setUseWildcardSearchMode(subCriteria.getCriteria() .isUseWildcardSearchMode()); break; + case SAMPLE_CHILD: + // merge all child sub criteria into one + childCriteria.getCriteria().addAll(subCriteria.getCriteria().getCriteria()); + childCriteria.setConnection(subCriteria.getCriteria().getConnection()); + childCriteria.setUseWildcardSearchMode(subCriteria.getCriteria() + .isUseWildcardSearchMode()); + break; default: otherSubCriterias.add(subCriteria); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleLister.java index 14f10d8f3f9..cb7a2445b17 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleLister.java @@ -66,8 +66,10 @@ public interface ISampleLister public List<SampleRelationShipSkeleton> listSampleRelationShipsBy( IValidator<SampleRelationShipSkeleton> criteria); - public Map<Long, Set<Long>> listParentIds(Collection<Long> childrenIds); + /** Returns a map from child id to set of parents ids for specified children. */ + public Map<Long, Set<Long>> getChildToParentsIdsMap(Collection<Long> childrenIds); - public Map<Long, Set<Long>> listChildrenIds(Collection<Long> parentIds); + /** Returns a map from parent id to set of children ids for specified parents. */ + public Map<Long, Set<Long>> getParentToChildrenIdsMap(Collection<Long> parentIds); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleLister.java index 39ad734c765..63ffe527675 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/SampleLister.java @@ -120,7 +120,7 @@ public class SampleLister implements ISampleLister return result; } - public Map<Long, Set<Long>> listParentIds(Collection<Long> childrenIds) + public Map<Long, Set<Long>> getChildToParentsIdsMap(Collection<Long> childrenIds) { LongOpenHashSet ids = new LongOpenHashSet(); for (Long id : childrenIds) @@ -145,7 +145,7 @@ public class SampleLister implements ISampleLister return map; } - public Map<Long, Set<Long>> listChildrenIds(Collection<Long> parentIds) + public Map<Long, Set<Long>> getParentToChildrenIdsMap(Collection<Long> parentIds) { LongOpenHashSet ids = new LongOpenHashSet(); for (Long id : parentIds) diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java index c8a9f4ca752..d645c3df48a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java @@ -19,12 +19,12 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed; import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.CODE; import ch.systemsx.cisd.common.exceptions.InternalErr; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AssociatedEntityKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetAttributeSearchFieldKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentAttributeSearchFieldKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialAttributeSearchFieldKind; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleAttributeSearchFieldKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AssociatedEntityKind; import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants; /** @@ -56,11 +56,12 @@ class IndexFieldNameHelper case SAMPLE_CONTAINER: if (entityKind == EntityKind.SAMPLE) { - return SearchFieldConstants.SAMPLE_ID; + return SearchFieldConstants.CONTAINER_ID; } throw createAssociationNotHandledException(entityKind, associationKind); case SAMPLE_PARENT: - // sample parent is a many-to-many connection - it is not handled by lucene index + case SAMPLE_CHILD: + // parent-child is a many-to-many connection - it is not handled by lucene index throw createAssociationNotHandledException(entityKind, associationKind); } return null; // shouldn't happen diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchSubCriteria.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchSubCriteria.java index ab2d31f0216..03f59d5a27d 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchSubCriteria.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchSubCriteria.java @@ -27,6 +27,11 @@ public class SearchSubCriteria implements Serializable return new SearchSubCriteria(SearchableEntityKind.SAMPLE_PARENT, criteria); } + public static SearchSubCriteria createSampleChildCriteria(SearchCriteria criteria) + { + return new SearchSubCriteria(SearchableEntityKind.SAMPLE_CHILD, criteria); + } + public static SearchSubCriteria createSampleContainerCriteria(SearchCriteria criteria) { return new SearchSubCriteria(SearchableEntityKind.SAMPLE_CONTAINER, criteria); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchableEntityKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchableEntityKind.java index 9b40de745aa..3414819537a 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchableEntityKind.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchableEntityKind.java @@ -9,5 +9,5 @@ public enum SearchableEntityKind { SAMPLE, EXPERIMENT, // sample subcriteria - SAMPLE_CONTAINER, SAMPLE_PARENT, // SAMPLE_CHILD + SAMPLE_CONTAINER, SAMPLE_PARENT, SAMPLE_CHILD } \ No newline at end of file diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AssociatedEntityKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AssociatedEntityKind.java index f5bea334d9e..e50c8df8b0e 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AssociatedEntityKind.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AssociatedEntityKind.java @@ -32,7 +32,9 @@ public enum AssociatedEntityKind implements ISerializable SAMPLE_CONTAINER("Container", EntityKind.SAMPLE), - SAMPLE_PARENT("Parent", EntityKind.SAMPLE); + SAMPLE_PARENT("Parent", EntityKind.SAMPLE), + + SAMPLE_CHILD("Child", EntityKind.SAMPLE); private final String description; diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java index 7a3fe63546d..567809831e1 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java @@ -382,9 +382,9 @@ public class SamplePE extends AttachmentHolderPE implements IIdAndCodeHolder, Co private Long getContainerId() { Long result = null; - if (getExperimentInternal() != null) + if (getContainer() != null) { - result = HibernateUtils.getId(getExperimentInternal()); + result = HibernateUtils.getId(getContainer()); assert result != null; } return result; diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceTest.java index a7375d49a12..55f584dbe43 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceTest.java @@ -264,6 +264,30 @@ public class GeneralInformationServiceTest extends AbstractServerTestCase context.assertIsSatisfied(); } + @Test + public void testSearchForSamplesWithChild() + { + prepareGetSession(); + final RecordingMatcher<DetailedSearchCriteria> detailedSearchCriteriaMatcher = + RecordingMatcher.create(); + final RecordingMatcher<List<DetailedSearchSubCriteria>> detailedSearchSubCriteriaMatcher = + RecordingMatcher.create(); + prepareSearchForSamples(detailedSearchCriteriaMatcher, detailedSearchSubCriteriaMatcher); + List<Sample> result = + service.searchForSamples(SESSION_TOKEN, createSearchCriteriaForSampleWithChild()); + assertEquals(1, result.size()); + Sample resultSample = result.get(0); + assertEquals("/space/code", resultSample.getIdentifier()); + assertEquals("ATTRIBUTE CODE: a code AND " + + "PROPERTY MY_PROPERTY2: a property value (with wildcards)", + detailedSearchCriteriaMatcher.recordedObject().toString()); + // check parent subcriteria + assertEquals("[SAMPLE_CHILD: ATTRIBUTE CODE: child code AND " + + "PROPERTY CHILD_PROPERTY: child property value (with wildcards)]", + detailedSearchSubCriteriaMatcher.recordedObject().toString()); + context.assertIsSatisfied(); + } + @Test public void testSearchForSamplesWithContainer() { @@ -498,6 +522,14 @@ public class GeneralInformationServiceTest extends AbstractServerTestCase return sc; } + private SearchCriteria createSearchCriteriaForSampleChild() + { + SearchCriteria sc = new SearchCriteria(); + sc.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "child code")); + sc.addMatchClause(MatchClause.createPropertyMatch("CHILD_PROPERTY", "child property value")); + return sc; + } + private SearchCriteria createSearchCriteriaForSampleContainer() { SearchCriteria sc = new SearchCriteria(); @@ -534,6 +566,14 @@ public class GeneralInformationServiceTest extends AbstractServerTestCase return mainCriteria; } + private SearchCriteria createSearchCriteriaForSampleWithChild() + { + SearchCriteria mainCriteria = createSearchCriteriaForSample(); + SearchCriteria childCriteria = createSearchCriteriaForSampleChild(); + mainCriteria.addSubCriteria(SearchSubCriteria.createSampleChildCriteria(childCriteria)); + return mainCriteria; + } + private SearchCriteria createSearchCriteriaForSampleWithContainer() { SearchCriteria mainCriteria = createSearchCriteriaForSample(); diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java index d27cfd3f9a0..030b5ce6207 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.openbis.systemtest.api.v1; import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; import java.util.ArrayList; @@ -170,6 +171,36 @@ public class GeneralInformationServiceTest extends SystemTestCase assertEquals(2, result.size()); } + @Test + public void testSearchForSamplesByChildCode() + { + // Search for Samples with only child's code limiting the results + SearchCriteria sc = new SearchCriteria(); + sc.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "*")); + SearchCriteria cc = new SearchCriteria(); + cc.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "3VCP*")); + sc.addSubCriteria(SearchSubCriteria.createSampleChildCriteria(cc)); + List<Sample> result = generalInformationService.searchForSamples(sessionToken, sc); + assertEquals(2, result.size()); + } + + @Test + public void testSearchForSamplesByContainerCode() + { + // Search for Samples with only container's code limiting the results + SearchCriteria sc = new SearchCriteria(); + sc.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "*")); + SearchCriteria cc = new SearchCriteria(); + cc.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE, "CL1")); + sc.addSubCriteria(SearchSubCriteria.createSampleContainerCriteria(cc)); + List<Sample> result = generalInformationService.searchForSamples(sessionToken, sc); + assertEquals(2, result.size()); + for (Sample s : result) + { + assertTrue(s.getCode() + "doesn't start with 'CL1:'", s.getCode().startsWith("CL1:")); + } + } + @Test public void testSearchForSamplesByExperimentAndParentCode() { -- GitLab