Skip to content
Snippets Groups Projects
Commit 04ca0c8b authored by tpylak's avatar tpylak
Browse files

LMS-1607 port screening datasets speed improvement from S83.x

SVN: 16902
parent 796fc9e6
No related branches found
No related tags found
No related merge requests found
...@@ -25,7 +25,6 @@ import java.util.Set; ...@@ -25,7 +25,6 @@ import java.util.Set;
import java.util.Map.Entry; import java.util.Map.Entry;
import ch.systemsx.cisd.bds.hcs.Location; import ch.systemsx.cisd.bds.hcs.Location;
import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
import ch.systemsx.cisd.openbis.dss.etl.ScreeningContainerDatasetInfoHelper.ExperimentWithChannelsAndContainer; import ch.systemsx.cisd.openbis.dss.etl.ScreeningContainerDatasetInfoHelper.ExperimentWithChannelsAndContainer;
import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
...@@ -62,6 +61,7 @@ public class HCSDatasetUploader ...@@ -62,6 +61,7 @@ public class HCSDatasetUploader
dao, info, channels); dao, info, channels);
long contId = basicStruct.getContainerId(); long contId = basicStruct.getContainerId();
Map<String, Long/* (tech id */> channelsMap = basicStruct.getChannelsMap(); Map<String, Long/* (tech id */> channelsMap = basicStruct.getChannelsMap();
Long[][] spotIds = getOrCreateSpots(contId, info, images); Long[][] spotIds = getOrCreateSpots(contId, info, images);
long datasetId = createDataset(contId, info); long datasetId = createDataset(contId, info);
...@@ -105,11 +105,11 @@ public class HCSDatasetUploader ...@@ -105,11 +105,11 @@ public class HCSDatasetUploader
{ {
Map<ImgChannelStackDTO, List<AcquiredImageInStack>> stackImagesMap = Map<ImgChannelStackDTO, List<AcquiredImageInStack>> stackImagesMap =
makeStackImagesMap(images, spotIds, datasetId); makeStackImagesMap(images, spotIds, datasetId);
createChannelStacks(stackImagesMap.keySet()); dao.addChannelStacks(new ArrayList<ImgChannelStackDTO>(stackImagesMap.keySet()));
createImages(stackImagesMap, channelsMap); createImages(stackImagesMap, channelsMap);
} }
private static Map<ImgChannelStackDTO, List<AcquiredImageInStack>> makeStackImagesMap( private Map<ImgChannelStackDTO, List<AcquiredImageInStack>> makeStackImagesMap(
List<AcquiredPlateImage> images, Long[][] spotIds, long datasetId) List<AcquiredPlateImage> images, Long[][] spotIds, long datasetId)
{ {
Map<ImgChannelStackDTO, List<AcquiredImageInStack>> map = Map<ImgChannelStackDTO, List<AcquiredImageInStack>> map =
...@@ -134,11 +134,12 @@ public class HCSDatasetUploader ...@@ -134,11 +134,12 @@ public class HCSDatasetUploader
.getThumbnailFilePathOrNull()); .getThumbnailFilePathOrNull());
} }
private static ImgChannelStackDTO makeStackDTO(AcquiredPlateImage image, Long[][] spotIds, private ImgChannelStackDTO makeStackDTO(AcquiredPlateImage image, Long[][] spotIds,
long datasetId) long datasetId)
{ {
long spotId = getSpotId(image, spotIds); long spotId = getSpotId(image, spotIds);
return new ImgChannelStackDTO(image.getTileRow(), image.getTileColumn(), datasetId, spotId); return new ImgChannelStackDTO(dao.createChannelStackId(), image.getTileRow(), image
.getTileColumn(), datasetId, spotId);
} }
private static long getSpotId(AcquiredPlateImage image, Long[][] spotIds) private static long getSpotId(AcquiredPlateImage image, Long[][] spotIds)
...@@ -153,62 +154,103 @@ public class HCSDatasetUploader ...@@ -153,62 +154,103 @@ public class HCSDatasetUploader
private void createImages(Map<ImgChannelStackDTO, List<AcquiredImageInStack>> stackImagesMap, private void createImages(Map<ImgChannelStackDTO, List<AcquiredImageInStack>> stackImagesMap,
Map<String, Long> channelsMap) Map<String, Long> channelsMap)
{ {
ImagesToCreate imagesToCreate =
new ImagesToCreate(new ArrayList<ImgImageDTO>(),
new ArrayList<ImgAcquiredImageDTO>());
for (Entry<ImgChannelStackDTO, List<AcquiredImageInStack>> entry : stackImagesMap for (Entry<ImgChannelStackDTO, List<AcquiredImageInStack>> entry : stackImagesMap
.entrySet()) .entrySet())
{ {
long stackId = entry.getKey().getId(); long stackId = entry.getKey().getId();
createImages(stackId, channelsMap, entry.getValue()); addImagesToCreate(imagesToCreate, stackId, channelsMap, entry.getValue());
} }
dao.addImages(imagesToCreate.getImages());
dao.addAcquiredImages(imagesToCreate.getAcquiredImages());
} }
private void createImages(long stackId, Map<String, Long> channelsMap, /**
List<AcquiredImageInStack> images) * Because we can have millions of images, we have to create them in batches. That is why we
* create all the DTOs first and generate ids for them before they are created in the database.
* Then we can save everything in one go.
*/
private void addImagesToCreate(ImagesToCreate imagesToCreate, long stackId,
Map<String, Long> channelsMap, List<AcquiredImageInStack> images)
{ {
List<ImgImageDTO> imageDTOs = imagesToCreate.getImages();
List<ImgAcquiredImageDTO> acquiredImageDTOs = imagesToCreate.getAcquiredImages();
for (AcquiredImageInStack image : images) for (AcquiredImageInStack image : images)
{ {
String channelName = image.getChannelName(); long channelTechId = channelsMap.get(image.getChannelName());
Long channelTechId = channelsMap.get(channelName);
if (channelTechId == null) ImgImageDTO imageDTO = mkImageWithIdDTO(image.getImageFilePath());
ImgImageDTO thumbnailDTO = tryMkImageWithIdDTO(image.getThumbnailPathOrNull());
Long thumbnailId = thumbnailDTO == null ? null : thumbnailDTO.getId();
ImgAcquiredImageDTO acquiredImage =
mkAcquiredImage(stackId, channelTechId, imageDTO.getId(), thumbnailId);
imageDTOs.add(imageDTO);
if (thumbnailDTO != null)
{ {
throw new EnvironmentFailureException("Invalid channel name " + channelName imageDTOs.add(thumbnailDTO);
+ ". Available channels: " + channelsMap.keySet());
} }
createImage(stackId, channelTechId, image); acquiredImageDTOs.add(acquiredImage);
}
}
private static class ImagesToCreate
{
private final List<ImgImageDTO> images;
private final List<ImgAcquiredImageDTO> acquiredImages;
public ImagesToCreate(List<ImgImageDTO> images, List<ImgAcquiredImageDTO> acquiredImages)
{
super();
this.images = images;
this.acquiredImages = acquiredImages;
}
public List<ImgImageDTO> getImages()
{
return images;
}
public List<ImgAcquiredImageDTO> getAcquiredImages()
{
return acquiredImages;
} }
} }
private void createImage(long stackId, long channelTechId, AcquiredImageInStack image) private ImgAcquiredImageDTO mkAcquiredImage(long stackId, long channelTechId, long imageId,
Long thumbnailId)
{ {
long imageId = addImage(image.getImageFilePath());
Long thumbnailId = addImage(image.getThumbnailPathOrNull());
ImgAcquiredImageDTO acquiredImage = new ImgAcquiredImageDTO(); ImgAcquiredImageDTO acquiredImage = new ImgAcquiredImageDTO();
acquiredImage.setImageId(imageId); acquiredImage.setImageId(imageId);
acquiredImage.setThumbnailId(thumbnailId); acquiredImage.setThumbnailId(thumbnailId);
acquiredImage.setChannelStackId(stackId); acquiredImage.setChannelStackId(stackId);
acquiredImage.setChannelId(channelTechId); acquiredImage.setChannelId(channelTechId);
dao.addAcquiredImage(acquiredImage); return acquiredImage;
} }
private Long addImage(RelativeImageReference imageReferenceOrNull) private ImgImageDTO tryMkImageWithIdDTO(RelativeImageReference imageReferenceOrNull)
{ {
if (imageReferenceOrNull == null) if (imageReferenceOrNull == null)
{ {
return null; return null;
} }
return dao.addImage(new ImgImageDTO(imageReferenceOrNull.getRelativeImagePath(), return mkImageWithIdDTO(imageReferenceOrNull);
imageReferenceOrNull.tryGetPage(), imageReferenceOrNull.tryGetColorComponent()));
} }
private void createChannelStacks(Set<ImgChannelStackDTO> stacks) private ImgImageDTO mkImageWithIdDTO(RelativeImageReference imageReferenceOrNull)
{ {
for (ImgChannelStackDTO stack : stacks) ImgImageDTO dto =
{ new ImgImageDTO(dao.createImageId(), imageReferenceOrNull.getRelativeImagePath(),
long id = dao.addChannelStack(stack); imageReferenceOrNull.tryGetPage(), imageReferenceOrNull
stack.setId(id); .tryGetColorComponent());
} return dto;
} }
// returns a matrix of spot tech ids. The matrix[row][col] contains null is spot at (row,col) // returns a matrix of spot tech ids. The matrix[row][col] contains null is
// spot at (row,col)
// does not exist. Spot coordinates are 0-based in the matrix. // does not exist. Spot coordinates are 0-based in the matrix.
private Long[][] getOrCreateSpots(long contId, ScreeningContainerDatasetInfo info, private Long[][] getOrCreateSpots(long contId, ScreeningContainerDatasetInfo info,
List<AcquiredPlateImage> images) List<AcquiredPlateImage> images)
......
...@@ -59,7 +59,7 @@ class BDSImagingDbUploader ...@@ -59,7 +59,7 @@ class BDSImagingDbUploader
private final IImagingQueryDAO dao; private final IImagingQueryDAO dao;
BDSImagingDbUploader(File dataset, IImagingQueryDAO dao, String originalDatasetDirName, public BDSImagingDbUploader(File dataset, IImagingQueryDAO dao, String originalDatasetDirName,
List<String> channelNames, List<ColorComponent> channelColorComponentsOrNull) List<String> channelNames, List<ColorComponent> channelColorComponentsOrNull)
{ {
this.dao = dao; this.dao = dao;
...@@ -70,7 +70,7 @@ class BDSImagingDbUploader ...@@ -70,7 +70,7 @@ class BDSImagingDbUploader
} }
boolean migrate() public boolean migrate()
{ {
List<AcquiredPlateImage> images = tryExtractMappings(); List<AcquiredPlateImage> images = tryExtractMappings();
if (images == null) if (images == null)
...@@ -154,7 +154,14 @@ class BDSImagingDbUploader ...@@ -154,7 +154,14 @@ class BDSImagingDbUploader
private static List<String> readLines(File mappingFile) throws IOException, private static List<String> readLines(File mappingFile) throws IOException,
FileNotFoundException FileNotFoundException
{ {
return IOUtils.readLines(new FileInputStream(mappingFile)); FileInputStream stream = new FileInputStream(mappingFile);
try
{
return IOUtils.readLines(stream);
} finally
{
stream.close();
}
} }
private List<AcquiredPlateImage> tryParseMappings(List<String> lines) private List<AcquiredPlateImage> tryParseMappings(List<String> lines)
......
...@@ -93,23 +93,37 @@ public interface IImagingQueryDAO extends TransactionQuery ...@@ -93,23 +93,37 @@ public interface IImagingQueryDAO extends TransactionQuery
@Select(value = "SELECT * from FEATURE_VALUES where FD_ID = ?{1.id}", resultSetBinding = FeatureVectorDataObjectBinding.class) @Select(value = "SELECT * from FEATURE_VALUES where FD_ID = ?{1.id}", resultSetBinding = FeatureVectorDataObjectBinding.class)
public List<ImgFeatureValuesDTO> getFeatureValues(ImgFeatureDefDTO featureDef); public List<ImgFeatureValuesDTO> getFeatureValues(ImgFeatureDefDTO featureDef);
// generate ids
@Select("select nextval('images_id_seq')")
public long createImageId();
@Select("select nextval('channel_stacks_id_seq')")
public long createChannelStackId();
// batch updates
@Update(sql = "insert into CHANNEL_STACKS (ID, X, Y, Z_in_M, T_in_SEC, DS_ID, SPOT_ID) values "
+ "(?{1.id}, ?{1.column}, ?{1.row}, ?{1.z}, ?{1.t}, ?{1.datasetId}, ?{1.spotId})", batchUpdate = true)
public void addChannelStacks(List<ImgChannelStackDTO> channelStacks);
@Update(sql = "insert into IMAGES (ID, PATH, PAGE, COLOR) values "
+ "(?{1.id}, ?{1.filePath}, ?{1.page}, ?{1.colorComponentAsString})", batchUpdate = true)
public void addImages(List<ImgImageDTO> images);
@Update(sql = "insert into ACQUIRED_IMAGES (IMG_ID, THUMBNAIL_ID, CHANNEL_STACK_ID, CHANNEL_ID) values "
+ "(?{1.imageId}, ?{1.thumbnailId}, ?{1.channelStackId}, ?{1.channelId})", batchUpdate = true)
public void addAcquiredImages(List<ImgAcquiredImageDTO> acquiredImages);
// inserts // inserts
@Select("insert into EXPERIMENTS (PERM_ID) values (?{1}) returning ID") @Select("insert into EXPERIMENTS (PERM_ID) values (?{1}) returning ID")
public long addExperiment(String experimentPermId); public long addExperiment(String experimentPermId);
@Select("insert into ACQUIRED_IMAGES (IMG_ID, THUMBNAIL_ID, CHANNEL_STACK_ID, CHANNEL_ID) values "
+ "(?{1.imageId}, ?{1.thumbnailId}, ?{1.channelStackId}, ?{1.channelId}) returning ID")
public long addAcquiredImage(ImgAcquiredImageDTO acquiredImage);
@Select("insert into CHANNELS (NAME, DESCRIPTION, WAVELENGTH, DS_ID, EXP_ID) values " @Select("insert into CHANNELS (NAME, DESCRIPTION, WAVELENGTH, DS_ID, EXP_ID) values "
+ "(?{1.name}, ?{1.description}, ?{1.wavelength}, ?{1.datasetId}, ?{1.experimentId}) returning ID") + "(?{1.name}, ?{1.description}, ?{1.wavelength}, ?{1.datasetId}, ?{1.experimentId}) returning ID")
public long addChannel(ImgChannelDTO channel); public long addChannel(ImgChannelDTO channel);
@Select("insert into CHANNEL_STACKS (X, Y, Z_in_M, T_in_SEC, DS_ID, SPOT_ID) values "
+ "(?{1.column}, ?{1.row}, ?{1.z}, ?{1.t}, ?{1.datasetId}, ?{1.spotId}) returning ID")
public long addChannelStack(ImgChannelStackDTO channelStack);
@Select("insert into CONTAINERS (PERM_ID, SPOTS_WIDTH, SPOTS_HEIGHT, EXPE_ID) values " @Select("insert into CONTAINERS (PERM_ID, SPOTS_WIDTH, SPOTS_HEIGHT, EXPE_ID) values "
+ "(?{1.permId}, ?{1.numberOfColumns}, ?{1.numberOfRows}, ?{1.experimentId}) returning ID") + "(?{1.permId}, ?{1.numberOfColumns}, ?{1.numberOfRows}, ?{1.experimentId}) returning ID")
public long addContainer(ImgContainerDTO container); public long addContainer(ImgContainerDTO container);
...@@ -119,10 +133,6 @@ public interface IImagingQueryDAO extends TransactionQuery ...@@ -119,10 +133,6 @@ public interface IImagingQueryDAO extends TransactionQuery
+ "?{1.fieldNumberOfRows}, ?{1.containerId}) returning ID") + "?{1.fieldNumberOfRows}, ?{1.containerId}) returning ID")
public long addDataset(ImgDatasetDTO dataset); public long addDataset(ImgDatasetDTO dataset);
@Select("insert into IMAGES (PATH, PAGE, COLOR) values "
+ "(?{1.filePath}, ?{1.page}, ?{1.colorComponentAsString}) returning ID")
public long addImage(ImgImageDTO image);
@Select("insert into SPOTS (X, Y, CONT_ID, PERM_ID) values " @Select("insert into SPOTS (X, Y, CONT_ID, PERM_ID) values "
+ "(?{1.column}, ?{1.row}, ?{1.containerId}, ?{1.permId}) returning ID") + "(?{1.column}, ?{1.row}, ?{1.containerId}, ?{1.permId}) returning ID")
public long addSpot(ImgSpotDTO spot); public long addSpot(ImgSpotDTO spot);
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
package ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess; package ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess;
import net.lemnik.eodsql.AutoGeneratedKeys;
import net.lemnik.eodsql.ResultColumn; import net.lemnik.eodsql.ResultColumn;
import ch.systemsx.cisd.common.utilities.AbstractHashable; import ch.systemsx.cisd.common.utilities.AbstractHashable;
...@@ -26,7 +25,7 @@ import ch.systemsx.cisd.common.utilities.AbstractHashable; ...@@ -26,7 +25,7 @@ import ch.systemsx.cisd.common.utilities.AbstractHashable;
*/ */
public class ImgChannelStackDTO extends AbstractHashable public class ImgChannelStackDTO extends AbstractHashable
{ {
@AutoGeneratedKeys @ResultColumn("ID")
private long id; private long id;
// x and y are kind of a two dimensional sequence number, (e.g. tile column) // x and y are kind of a two dimensional sequence number, (e.g. tile column)
...@@ -58,8 +57,9 @@ public class ImgChannelStackDTO extends AbstractHashable ...@@ -58,8 +57,9 @@ public class ImgChannelStackDTO extends AbstractHashable
// All Data-Object classes must have a default constructor. // All Data-Object classes must have a default constructor.
} }
public ImgChannelStackDTO(int row, int column, long datasetId, long spotId) public ImgChannelStackDTO(long id, int row, int column, long datasetId, long spotId)
{ {
this.id = id;
this.row = row; this.row = row;
this.column = column; this.column = column;
this.datasetId = datasetId; this.datasetId = datasetId;
......
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
package ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess; package ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess;
import net.lemnik.eodsql.AutoGeneratedKeys;
import net.lemnik.eodsql.ResultColumn; import net.lemnik.eodsql.ResultColumn;
import ch.systemsx.cisd.common.utilities.AbstractHashable; import ch.systemsx.cisd.common.utilities.AbstractHashable;
...@@ -27,7 +25,7 @@ import ch.systemsx.cisd.common.utilities.AbstractHashable; ...@@ -27,7 +25,7 @@ import ch.systemsx.cisd.common.utilities.AbstractHashable;
*/ */
public class ImgImageDTO extends AbstractHashable public class ImgImageDTO extends AbstractHashable
{ {
@AutoGeneratedKeys @ResultColumn("id")
private long id; private long id;
@ResultColumn("PATH") @ResultColumn("PATH")
...@@ -45,8 +43,10 @@ public class ImgImageDTO extends AbstractHashable ...@@ -45,8 +43,10 @@ public class ImgImageDTO extends AbstractHashable
// All Data-Object classes must have a default constructor. // All Data-Object classes must have a default constructor.
} }
public ImgImageDTO(String filePath, Integer pageOrNull, ColorComponent colorComponentOrNull) public ImgImageDTO(long id, String filePath, Integer pageOrNull,
ColorComponent colorComponentOrNull)
{ {
this.id = id;
this.filePath = filePath; this.filePath = filePath;
this.pageOrNull = pageOrNull; this.pageOrNull = pageOrNull;
this.colorComponentOrNull = this.colorComponentOrNull =
......
...@@ -20,6 +20,7 @@ import static org.testng.AssertJUnit.assertEquals; ...@@ -20,6 +20,7 @@ import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNotNull;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.testng.AssertJUnit; import org.testng.AssertJUnit;
...@@ -148,8 +149,8 @@ public class ImagingQueryDAOTest extends AbstractDBTest ...@@ -148,8 +149,8 @@ public class ImagingQueryDAOTest extends AbstractDBTest
|| channels[1] == channelId1 && channels[0] == channelId2); || channels[1] == channelId1 && channels[0] == channelId2);
// test get id of first channel // test get id of first channel
assertEquals(channels[0], dao.tryGetChannelIdByChannelNameDatasetIdOrExperimentId(datasetId, assertEquals(channels[0], dao.tryGetChannelIdByChannelNameDatasetIdOrExperimentId(
experimentId, "dsChannel").intValue()); datasetId, experimentId, "dsChannel").intValue());
List<ImgChannelDTO> experimentChannels = dao.getChannelsByExperimentId(experimentId); List<ImgChannelDTO> experimentChannels = dao.getChannelsByExperimentId(experimentId);
assertEquals(1, experimentChannels.size()); assertEquals(1, experimentChannels.size());
...@@ -164,8 +165,9 @@ public class ImagingQueryDAOTest extends AbstractDBTest ...@@ -164,8 +165,9 @@ public class ImagingQueryDAOTest extends AbstractDBTest
private long addImage(String path, ColorComponent colorComponent) private long addImage(String path, ColorComponent colorComponent)
{ {
final ImgImageDTO image = new ImgImageDTO(path, PAGE, colorComponent); final ImgImageDTO image = new ImgImageDTO(dao.createImageId(), path, PAGE, colorComponent);
return dao.addImage(image); dao.addImages(Arrays.asList(image));
return image.getId();
} }
private long addExperiment() private long addExperiment()
...@@ -243,17 +245,20 @@ public class ImagingQueryDAOTest extends AbstractDBTest ...@@ -243,17 +245,20 @@ public class ImagingQueryDAOTest extends AbstractDBTest
private long addChannelStack(long datasetId, long spotId) private long addChannelStack(long datasetId, long spotId)
{ {
final ImgChannelStackDTO channelStack = final ImgChannelStackDTO channelStack =
new ImgChannelStackDTO(Y_TILE_ROW, X_TILE_COLUMN, datasetId, spotId); new ImgChannelStackDTO(dao.createChannelStackId(), Y_TILE_ROW, X_TILE_COLUMN,
return dao.addChannelStack(channelStack); datasetId, spotId);
dao.addChannelStacks(Arrays.asList(channelStack));
return channelStack.getId();
} }
private long addAcquiredImage(long imageId, long channelStackId, long channelId) private void addAcquiredImage(long imageId, long channelStackId, long channelId)
{ {
final ImgAcquiredImageDTO acquiredImage = new ImgAcquiredImageDTO(); final ImgAcquiredImageDTO acquiredImage = new ImgAcquiredImageDTO();
acquiredImage.setImageId(imageId); acquiredImage.setImageId(imageId);
acquiredImage.setChannelStackId(channelStackId); acquiredImage.setChannelStackId(channelStackId);
acquiredImage.setChannelId(channelId); acquiredImage.setChannelId(channelId);
return dao.addAcquiredImage(acquiredImage);
dao.addAcquiredImages(Arrays.asList(acquiredImage));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment