diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IScreeningQuery.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IScreeningQuery.java index 8fbef51d14e0c19b03dea292b00b80831e71981f..8b53b36ed7d38cec3b8b2ea570f27d4dd7bed922 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IScreeningQuery.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IScreeningQuery.java @@ -208,9 +208,10 @@ public interface IScreeningQuery extends BaseQuery + " join sample_properties well_props on well_props.samp_id = well.id " + " join materials well_material on well_props.mate_prop_id = well_material.id " + " join material_types well_material_type on well_material.maty_id = well_material_type.id " - + "where pl.samp_id_part_of is null and exp.id = ?{1} " - + " and well_material_type.code similar to ?{2}", fetchSize = FETCH_SIZE) - public List<BasicWellContentQueryResult> getPlateLocationsForExperiment(long experimentId, + + "where pl.samp_id_part_of is null and exp.id = any(?{1}) " + + " and well_material_type.code similar to ?{2}", parameterBindings = + { LongArrayMapper.class, TypeMapper.class /* default mapper */}, fetchSize = FETCH_SIZE) + public List<BasicWellContentQueryResult> getPlateLocationsForExperiment(long[] experimentId, String materialTypesPattern); /** diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java index f239027e303571f2c31cbafb5492d4f076cb7931..83cf56f5a51905b7230db9aea0f0b63551861e59 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java @@ -58,6 +58,8 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoa */ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoader { + private static final Integer MAX_ANALYSIS_DATASETS_IN_BATCH = 100; + public static List<MaterialSimpleFeatureVectorSummary> loadMaterialFeatureVectorsFromAllAssays( Session session, IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory, TechId materialId, TechId projectTechIdOrNull, @@ -122,19 +124,31 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa this.screeningQuery = screeningQuery; } - private List<BasicWellContentQueryResult> fetchWellLocations(ExperimentReference experiment) + private List<BasicWellContentQueryResult> fetchWellLocations( + List<ExperimentReference> experiments) { StopWatch watch = createWatchAndStart(); String materialTypePattern = PatternMatchingUtils.asPostgresSimilarExpression(settings .getReplicaMatrialTypeSubstrings()); List<BasicWellContentQueryResult> wells = - screeningQuery.getPlateLocationsForExperiment(experiment.getId(), + screeningQuery.getPlateLocationsForExperiment(extractIds(experiments), materialTypePattern); operationLog.info("[" + watch.getTime() + " msec] Fetching " + wells.size() + " wells."); return wells; } + private static long[] extractIds(List<ExperimentReference> experiments) + { + long[] ids = new long[experiments.size()]; + int i = 0; + for (ExperimentReference experiment : experiments) + { + ids[i++] = experiment.getId(); + } + return ids; + } + /** * Note that different experiments can have different set of features! */ @@ -144,56 +158,96 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa List<MaterialSimpleFeatureVectorSummary> summaries = new ArrayList<MaterialSimpleFeatureVectorSummary>(); StopWatch globalWatch = createWatchAndStart(); - int totalWellsLoaded = 0; - int totalFeatureVectorsLoaded = 0; - for (ExperimentReference experiment : experiments) + List<ExperimentReference> experimentsBatch = new ArrayList<ExperimentReference>(); + long datasetsInBatch = 0; + for (int i = 0; i < experiments.size(); i++) { - StopWatch watch = createWatchAndStart(); - if (hasAnalysisDatasets(experiment) == false) + ExperimentReference experiment = experiments.get(i); + int datasetsNum = countAnalysisDatasets(experiment); + operationLog.info(String.format("Experiment %s contains %d analysis datasets", + experiment, datasetsNum)); + if (datasetsNum == 0) { // avoid loading all the wells if there are no analysis datasets summaries.add(new MaterialSimpleFeatureVectorSummary(experiment)); } else { - List<BasicWellContentQueryResult> allWells = fetchWellLocations(experiment); - totalWellsLoaded += allWells.size(); - Set<PlateIdentifier> plates = extractPlates(allWells); - WellFeatureCollection<FeatureVectorValues> allWellFeaturesOrNull = - tryLoadWellSingleFeatureVectors(plates); - if (allWellFeaturesOrNull == null) - { - summaries.add(new MaterialSimpleFeatureVectorSummary(experiment)); - } else - { - totalFeatureVectorsLoaded += allWellFeaturesOrNull.getFeatures().size(); - Map<WellReference, Long/* material id */> wellToMaterialMap = - createWellToMaterialMap(allWells); - - MaterialSimpleFeatureVectorSummary summary = - calculateExperimentFeatureVectorSummary(materialId, experiment, - allWellFeaturesOrNull, wellToMaterialMap); - summaries.add(summary); - operationLog.info("[" + watch.getTime() - + " msec] Fetching analysis summary for experiment " + experiment - + " done."); - - } + datasetsInBatch += datasetsNum; + experimentsBatch.add(experiment); + } + if (datasetsInBatch >= MAX_ANALYSIS_DATASETS_IN_BATCH + || (i == experiments.size() - 1 && experimentsBatch.isEmpty() == false)) + { + operationLog.info(String.format("Processing %d experiments with %d datasets: %s", + experimentsBatch.size(), datasetsInBatch, experimentsBatch)); + List<MaterialSimpleFeatureVectorSummary> batchSummaries = + loadMaterialFeatureVectorsFromAllAssaysBatch(materialId, experimentsBatch); + summaries.addAll(batchSummaries); + experimentsBatch.clear(); + datasetsInBatch = 0; + } + } + operationLog.info(String.format( + "[%d msec] Fetching and calculating analysis summaries for %d experiments.", + globalWatch.getTime(), summaries.size())); + return summaries; + } + + // load all experiments in a constant number of selects + private List<MaterialSimpleFeatureVectorSummary> loadMaterialFeatureVectorsFromAllAssaysBatch( + TechId materialId, List<ExperimentReference> experiments) + { + List<MaterialSimpleFeatureVectorSummary> summaries = + new ArrayList<MaterialSimpleFeatureVectorSummary>(); + StopWatch watch = createWatchAndStart(); + int totalWellsLoaded = 0; + int totalFeatureVectorsLoaded = 0; + + List<BasicWellContentQueryResult> allWells = fetchWellLocations(experiments); + totalWellsLoaded += allWells.size(); + Set<PlateIdentifier> plates = extractPlates(allWells); + WellFeatureCollection<FeatureVectorValues> allWellFeaturesOrNull = + tryLoadWellSingleFeatureVectors(plates); + + if (allWellFeaturesOrNull == null) + { + addEmptySummaries(summaries, experiments); + } else + { + for (ExperimentReference experiment : experiments) + { + totalFeatureVectorsLoaded += allWellFeaturesOrNull.getFeatures().size(); + Map<WellReference, Long/* material id */> wellToMaterialMap = + createWellToMaterialMapForExperiment(allWells, experiment); + + MaterialSimpleFeatureVectorSummary summary = + calculateExperimentFeatureVectorSummary(materialId, experiment, + allWellFeaturesOrNull, wellToMaterialMap); + summaries.add(summary); } } - operationLog - .info(String - .format("Fetching all experiment analysis summary took %d msec. Total wells loaded: %d, feature vectors: %d.", - globalWatch.getTime(), totalWellsLoaded, totalFeatureVectorsLoaded)); + operationLog.info(String.format( + "[%d msec] Experiments batch: %d, wells loaded: %d, feature vectors: %d.", + watch.getTime(), experiments.size(), totalWellsLoaded, totalFeatureVectorsLoaded)); return summaries; } - private boolean hasAnalysisDatasets(ExperimentReference experiment) + private void addEmptySummaries(List<MaterialSimpleFeatureVectorSummary> summaries, + List<ExperimentReference> experiments) + { + for (ExperimentReference experiment : experiments) + { + summaries.add(new MaterialSimpleFeatureVectorSummary(experiment)); + } + } + + private int countAnalysisDatasets(ExperimentReference experiment) { List<TechId> experiments = Arrays.asList(new TechId(experiment.getId())); IDatasetLister lister = businessObjectFactory.createDatasetLister(session); List<ExternalData> datasets = lister.listByExperimentTechIds(experiments); - return ScreeningUtils.filterImageAnalysisDatasets(datasets).size() > 0; + return ScreeningUtils.filterImageAnalysisDatasets(datasets).size(); } private StopWatch createWatchAndStart() @@ -203,33 +257,47 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa return watch; } - private static Map<WellReference, Long/* material id */> createWellToMaterialMap( - List<BasicWellContentQueryResult> wells) + private static Map<WellReference, Long/* material id */> createWellToMaterialMapForExperiment( + List<BasicWellContentQueryResult> wells, ExperimentReference experiment) { Map<WellReference, Long> wellToMaterialMap = new HashMap<WellReference, Long>(); for (BasicWellContentQueryResult well : wells) { - WellReference wellReference = createWellReference(well); - wellToMaterialMap.put(wellReference, well.material_content_id); + if (belongsToExperiment(well, experiment)) + { + WellReference wellReference = createWellReference(well); + wellToMaterialMap.put(wellReference, well.material_content_id); + } } return wellToMaterialMap; } + private static boolean belongsToExperiment(BasicWellContentQueryResult well, + ExperimentReference experiment) + { + return well.exp_perm_id.equals(experiment.getPermId()); + } + private static WellReference createWellReference(BasicWellContentQueryResult well) { WellLocation wellLocation = WellLocation.parseLocationStr(well.well_code); return new WellReference(wellLocation, well.plate_perm_id); } + /** + * @param experimentWellToMaterialMap wells belonging to the specified experiment + * @param allFeatures all features, not only for the specified experiment but possibly also for + * few others + */ private MaterialSimpleFeatureVectorSummary calculateExperimentFeatureVectorSummary( TechId materialId, ExperimentReference experiment, - WellFeatureCollection<FeatureVectorValues> experimentFeatures, - Map<WellReference, Long> wellToMaterialMap) + WellFeatureCollection<FeatureVectorValues> allFeatures, + Map<WellReference, Long> experimentWellToMaterialMap) { // we have to calculate summaries for all materials in the experiment to get the right // ranking of the specified material List<IWellData> experimentWellData = - createWellData(wellToMaterialMap, experimentFeatures.getFeatures()); + createWellData(experimentWellToMaterialMap, allFeatures.getFeatures()); List<MaterialIdFeatureVectorSummary> experimentSummaries = WellReplicaSummaryCalculator.calculateReplicasFeatureVectorSummaries( experimentWellData, settings.getAggregationType(), false); @@ -238,8 +306,8 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa MaterialIdFeatureVectorSummary materialSummary = findMaterialSummary(materialId, experimentSummaries); return new MaterialSimpleFeatureVectorSummary(experiment, - experimentFeatures.getFeatureCodesAndLabels(), - materialSummary.getFeatureVectorSummary(), materialSummary.getFeatureVectorRanks()); + allFeatures.getFeatureCodesAndLabels(), materialSummary.getFeatureVectorSummary(), + materialSummary.getFeatureVectorRanks()); } private MaterialIdFeatureVectorSummary findMaterialSummary(TechId materialId, @@ -258,13 +326,13 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa // connects each well with a material with its feature vector private static List<IWellData> createWellData( - Map<WellReference, Long/* material id */> wellToMaterialMap, - List<FeatureVectorValues> features) + Map<WellReference, Long/* material id */> experimentWellToMaterialMap, + List<FeatureVectorValues> allFeatures) { List<IWellData> experimentWellDataList = new ArrayList<IWellData>(); - for (FeatureVectorValues feature : features) + for (FeatureVectorValues feature : allFeatures) { - Long materialId = wellToMaterialMap.get(feature.getWellReference()); + Long materialId = experimentWellToMaterialMap.get(feature.getWellReference()); if (materialId != null) { float[] values = WellFeatureCollectionLoader.asFeatureVectorValues(feature); diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java index 08a2026c2b8a4473e20cc0ebc10e39c7a4ba5701..1b06ae8365d152e697187daf9b05e0b7ea286c6b 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java @@ -177,7 +177,8 @@ public class ScreeningDAOTest extends AbstractScreeningDAOTest public void testGetGlobalBasicPlateLocations() { List<BasicWellContentQueryResult> locations = - EntityListingTestUtils.asList(query.getPlateLocationsForExperiment(1, "%GENE%")); + EntityListingTestUtils.asList(query.getPlateLocationsForExperiment(new long[] + { 1, 2 }, "%GENE%")); AssertJUnit.assertEquals(0, locations.size()); List<ExperimentReferenceQueryResult> experiments = query.getExperimentsWithMaterial(1);