diff --git a/gemma-cli/src/test/java/ubic/gemma/core/apps/NCBIGene2GOAssociationLoaderCLITest.java b/gemma-cli/src/test/java/ubic/gemma/core/apps/NCBIGene2GOAssociationLoaderCLITest.java
index 3afdd45593..fcbf23dc57 100644
--- a/gemma-cli/src/test/java/ubic/gemma/core/apps/NCBIGene2GOAssociationLoaderCLITest.java
+++ b/gemma-cli/src/test/java/ubic/gemma/core/apps/NCBIGene2GOAssociationLoaderCLITest.java
@@ -1,6 +1,7 @@
package ubic.gemma.core.apps;
import gemma.gsec.authentication.ManualAuthenticationService;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,7 +25,6 @@
import static org.mockito.Mockito.*;
import static ubic.gemma.core.util.test.Assumptions.assumeThatResourceIsAvailable;
-@Category(SlowTest.class)
@ContextConfiguration
@TestExecutionListeners(WithSecurityContextTestExecutionListener.class)
public class NCBIGene2GOAssociationLoaderCLITest extends BaseCliTest {
@@ -79,6 +79,8 @@ public PersisterHelper persisterHelper() {
private ExternalDatabaseService externalDatabaseService;
@Test
+ @Ignore("This test is too slow, see https://github.com/PavlidisLab/Gemma/issues/1056 for details")
+ @Category(SlowTest.class)
@WithMockUser(authorities = { "GROUP_ADMIN" })
public void test() throws Exception {
assumeThatResourceIsAvailable( "ftp://ftp.ncbi.nih.gov/gene/DATA/gene2go.gz" );
diff --git a/gemma-cli/src/test/java/ubic/gemma/core/util/test/BaseCliTest.java b/gemma-cli/src/test/java/ubic/gemma/core/util/test/BaseCliTest.java
index 4413c44cd1..6da0450626 100644
--- a/gemma-cli/src/test/java/ubic/gemma/core/util/test/BaseCliTest.java
+++ b/gemma-cli/src/test/java/ubic/gemma/core/util/test/BaseCliTest.java
@@ -2,12 +2,12 @@
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
-import ubic.gemma.persistence.util.SpringProfiles;
+import ubic.gemma.persistence.util.EnvironmentProfiles;
/**
* Minimal setup
*/
-@ActiveProfiles({ "cli", SpringProfiles.TEST })
+@ActiveProfiles({ "cli", EnvironmentProfiles.TEST })
public abstract class BaseCliTest extends AbstractJUnit4SpringContextTests {
}
diff --git a/gemma-core/pom.xml b/gemma-core/pom.xml
index 29d94a385f..31a8933710 100644
--- a/gemma-core/pom.xml
+++ b/gemma-core/pom.xml
@@ -3,7 +3,7 @@
gemmagemma
- 1.31.1
+ 1.31.24.0.0gemma-core
diff --git a/gemma-core/src/main/java/ubic/gemma/core/analysis/expression/diff/LinearModelAnalyzer.java b/gemma-core/src/main/java/ubic/gemma/core/analysis/expression/diff/LinearModelAnalyzer.java
index 7ccf21a933..bb24b7c786 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/analysis/expression/diff/LinearModelAnalyzer.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/analysis/expression/diff/LinearModelAnalyzer.java
@@ -27,6 +27,7 @@
import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import ubic.basecode.dataStructure.matrix.DenseDoubleMatrix;
@@ -71,7 +72,7 @@
*/
@Component
@Scope(value = "prototype")
-public class LinearModelAnalyzer extends AbstractDifferentialExpressionAnalyzer {
+public class LinearModelAnalyzer extends AbstractDifferentialExpressionAnalyzer implements DisposableBean {
/**
* Preset levels for which we will store the HitListSizes.
@@ -123,7 +124,7 @@ public static DoubleMatrix makeDataMatrix( ObjectMatrix columnsToUse ) {
+ public static BioAssayDimension createBADMap( List columnsToUse ) {
/*
* Indices of the biomaterials in the original matrix.
*/
@@ -143,6 +144,18 @@ private static BioAssayDimension createBADMap( List columnsToUse )
return reorderedDim;
}
+ /**
+ * Executor used for performing analyses in the background while the current thread is reporting progress.
+ *
+ * This bean is using the prototype scope, so a single-thread executor is suitable to prevent concurrent analyses.
+ */
+ private final ExecutorService executorService = Executors.newSingleThreadExecutor();
+
+ @Override
+ public void destroy() throws Exception {
+ executorService.shutdown();
+ }
+
/**
* Determine if any factor should be treated as the intercept term.
*/
@@ -383,10 +396,6 @@ public Collection run( ExpressionExperiment expr
throw new RuntimeException( String.format( "There are no processed EVs for %s.", expressionExperiment ) );
}
- /*
- * FIXME remove flagged outlier samples ... at some point; so we don't carry NaNs around unnecessarily.
- */
-
return this.run( expressionExperiment, dmatrix, config );
}
@@ -1097,7 +1106,7 @@ private DifferentialExpressionAnalysis makeAnalysisEntity( BioAssaySet bioAssayS
expressionAnalysis.setDescription( "Linear model with " + config.getFactorsToInclude().size() + " factors"
+ ( interceptFactor == null ? "" : " with intercept treated as factor" )
+ ( interactionFactorLists.isEmpty() ? "" : " with interaction" )
- + ( subsetFactorValue == null ? "" : "Using subset " + bioAssaySet + " subset value= " + subsetFactorValue ) );
+ + ( subsetFactorValue == null ? "" : " Using subset " + bioAssaySet + " subset value= " + subsetFactorValue ) );
expressionAnalysis.setSubsetFactorValue( subsetFactorValue );
Set resultSets = this
@@ -1367,7 +1376,7 @@ private Map runAnalysis( final DoubleMatrix> f = Executors.newSingleThreadExecutor().submit( () -> {
+ Future
- *
- * If any factor is continuous, we sort by it and don't do any further sorting.
*
- * Otherwise, for categorical factors, we sort recursively (by levels of the first factor, then
+ * For categorical factors, we sort recursively (by levels of the first factor, then
* within that by levels of the second factor etc.)
*
* Any batch factor is used last (we sort by batch only within the most granular factor's levels)
@@ -610,12 +661,6 @@ private static List orderBiomaterialsBySortedFactors( List ordered = ExpressionDataMatrixColumnSort.orderByFactor( simplest, fv2bms, start );
- // Abort ordering, so we are ordered only by the first continuous factor.
- if ( ExperimentalDesignUtils.isContinuous( simplest ) ) {
- assert ordered != null;
- return ordered;
- }
-
LinkedList factorsStillToDo = new LinkedList<>();
factorsStillToDo.addAll( factors );
factorsStillToDo.remove( simplest );
diff --git a/gemma-core/src/main/java/ubic/gemma/core/datastructure/matrix/MatrixWriter.java b/gemma-core/src/main/java/ubic/gemma/core/datastructure/matrix/MatrixWriter.java
index e0ebe41c8f..d6f858f060 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/datastructure/matrix/MatrixWriter.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/datastructure/matrix/MatrixWriter.java
@@ -44,7 +44,7 @@
public class MatrixWriter extends AbstractFileService> {
public void write( Writer writer, ExpressionDataMatrix> matrix,
- Map> geneAnnotations, boolean writeHeader, boolean orderByDesign )
+ @Nullable Map> geneAnnotations, boolean writeHeader, boolean orderByDesign )
throws IOException {
this.write( writer, matrix, geneAnnotations, writeHeader, true, true, orderByDesign );
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSearchServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSearchServiceImpl.java
index 9850096eef..2d5eef3706 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSearchServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSearchServiceImpl.java
@@ -27,7 +27,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;
-import ubic.basecode.ontology.search.OntologySearchException;
import ubic.gemma.core.genome.gene.*;
import ubic.gemma.core.ontology.providers.GeneOntologyService;
import ubic.gemma.core.search.*;
@@ -245,8 +244,10 @@ public Collection searchGenesAndGeneGroups( String qu
taxon = geneSetService.getTaxon( gs );
GeneSetValueObject gsVo = geneSetValueObjectHelper.convertToValueObject( gs );
srDo = new SearchResultDisplayObject( gsVo );
- srDo.setTaxonId( taxon.getId() );
- srDo.setTaxonName( taxon.getCommonName() );
+ if ( taxon != null ) {
+ srDo.setTaxonId( taxon.getId() );
+ srDo.setTaxonName( taxon.getCommonName() );
+ }
geneSets.add( srDo );
}
taxon = null;
@@ -404,9 +405,11 @@ private List> retainGeneSetsOfThisTaxon( Long taxonId, Lis
for ( SearchResult sr : geneSetSearchResults ) {
GeneSet gs = sr.getResultObject();
if ( gs != null ) {
- GeneSetValueObject gsVo = geneSetValueObjectHelper.convertToValueObject( gs );
+ Set geneSetTaxaIds = geneSetService.getTaxa( gs ).stream()
+ .map( Taxon::getId )
+ .collect( Collectors.toSet() );
isSetOwnedByUser.put( gs.getId(), securityService.isOwnedByCurrentUser( gs ) );
- if ( Objects.equals( gsVo.getTaxonId(), taxonId ) ) {
+ if ( geneSetTaxaIds.contains( taxonId ) ) {
taxonCheckedSets.add( sr );
}
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetService.java b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetService.java
index 762dee961b..dd6cb3c64f 100755
--- a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetService.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetService.java
@@ -38,6 +38,7 @@
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* Service for managing gene sets
@@ -152,7 +153,7 @@ public interface GeneSetService extends BaseService, BaseVoEnabledServi
* @see GeneSetDao GeneSetDao for security filtering
*/
@Secured({ "IS_AUTHENTICATED_ANONYMOUSLY", "AFTER_ACL_COLLECTION_READ" })
- Collection loadAll( Taxon tax );
+ Collection loadAll( @Nullable Taxon tax );
/**
* Returns the {@link GeneSet}s for the currently logged in {@link User} - i.e, ones for which the current user has
@@ -303,10 +304,16 @@ Collection updateDatabaseEntity(
* all the genes
*
* @param geneSet gene set
- * @return the taxon or null if the gene set param was null
+ * @return a taxon, or null if the gene set has no member
*/
+ @Nullable
Taxon getTaxon( GeneSet geneSet );
+ /**
+ * Obtain all the taxa for the members of a given gene set.
+ */
+ Set getTaxa( GeneSet geneSet );
+
@Override
@Secured({ "GROUP_USER", "ACL_SECURABLE_EDIT" })
void update( GeneSet entity );
diff --git a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetServiceImpl.java
index c2566e8a79..fad346956c 100755
--- a/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/genome/gene/service/GeneSetServiceImpl.java
@@ -121,7 +121,7 @@ public Collection findByName( String name, Taxon taxon ) {
@Override
@Transactional(readOnly = true)
- public Collection loadAll( Taxon tax ) {
+ public Collection loadAll( @Nullable Taxon tax ) {
return this.geneSetDao.loadAll( tax );
}
@@ -487,12 +487,13 @@ public TaxonValueObject getTaxonVOforGeneSetVO( SessionBoundGeneSetValueObject g
@Override
@Transactional(readOnly = true)
public Taxon getTaxon( GeneSet geneSet ) {
- if ( geneSet == null )
- return null;
- Taxon tmpTax;
- tmpTax = geneSetDao.getTaxon( geneSet.getId() );
+ return geneSetDao.getTaxon( geneSet );
+ }
- return tmpTax;
+ @Override
+ @Transactional(readOnly = true)
+ public Set getTaxa( GeneSet geneSet ) {
+ return new HashSet<>( geneSetDao.getTaxa( geneSet ) );
}
private void checkGeneList( GeneSet gset, Collection updatedGenelist, Collection genes ) {
diff --git a/gemma-core/src/main/java/ubic/gemma/core/job/executor/webapp/TaskRunningServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/job/executor/webapp/TaskRunningServiceImpl.java
index c865b22f7f..7b630980d1 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/job/executor/webapp/TaskRunningServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/job/executor/webapp/TaskRunningServiceImpl.java
@@ -20,6 +20,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.concurrent.DelegatingSecurityContextCallable;
import org.springframework.stereotype.Component;
@@ -44,7 +45,7 @@
*/
// Valid, inspection is not parsing the context file for some reason
@Component
-public class TaskRunningServiceImpl implements TaskRunningService {
+public class TaskRunningServiceImpl implements TaskRunningService, DisposableBean {
private static final Log log = LogFactory.getLog( TaskRunningServiceImpl.class );
private final ExecutorService executorService = Executors.newFixedThreadPool( 20 );
private final Map submittedTasks = new ConcurrentHashMap<>();
@@ -54,6 +55,19 @@ public class TaskRunningServiceImpl implements TaskRunningService {
@Autowired
private TaskPostProcessing taskPostProcessing;
+ @Override
+ public void destroy() throws Exception {
+ log.info( "Shutting down TaskRunningService executor..." );
+ executorService.shutdown();
+ if ( !executorService.isTerminated() ) {
+ log.warn( "There are still running tasks, will wait at most 5 minutes before shutting them down." );
+ }
+ if ( !executorService.awaitTermination( 5, TimeUnit.MINUTES ) ) {
+ log.info( "TaskRunningService executor was still running after 5 minutes, interrupting pending tasks..." );
+ executorService.shutdownNow();
+ }
+ }
+
@Override
public SubmittedTask getSubmittedTask( String taskId ) {
return submittedTasks.get( taskId );
diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/association/phenotype/PhenotypeProcessingUtil.java b/gemma-core/src/main/java/ubic/gemma/core/loader/association/phenotype/PhenotypeProcessingUtil.java
index 21033fe5b1..e586c01f30 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/loader/association/phenotype/PhenotypeProcessingUtil.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/loader/association/phenotype/PhenotypeProcessingUtil.java
@@ -562,7 +562,7 @@ private void parseManualMappingFile() throws IOException {
if ( ontologyTerm != null ) {
- if ( ontologyTerm.getLabel().equalsIgnoreCase( valueStaticFile ) ) {
+ if ( valueStaticFile.equalsIgnoreCase( ontologyTerm.getLabel() ) ) {
if ( manualDescriptionToValuesUriMapping.get( termId ) != null ) {
col = manualDescriptionToValuesUriMapping.get( termId );
@@ -917,8 +917,12 @@ private boolean findUsingManualMappingFile( String meshOrOmimId, String annotato
meshOrOmimId + this.findExtraInfoMeshDescription( meshOrOmimId ) + " PARENT: (" );
for ( OntologyTerm o : onParents ) {
-
- String meshId = this.changeToId( o.getUri() );
+ String termUri = o.getUri();
+ if ( termUri == null ) {
+ log.warn( "Ignoring free-text term " + o );
+ continue;
+ }
+ String meshId = this.changeToId( termUri );
Collection uri = this.findManualMappingTermValueUri( meshId );
if ( uri != null && !uri.isEmpty() ) {
phenotypesUri.addAll( uri );
@@ -1185,8 +1189,13 @@ private Map> meshToDiseaseTerms( Collection> diseaseTerms = new HashMap<>();
for ( OntologyTerm m : meshTerms ) {
+ String termUri = m.getUri();
+ if ( termUri == null ) {
+ log.warn( "Ignoring free-text term: " + m );
+ continue;
+ }
- String meshId = this.changeToId( m.getUri() );
+ String meshId = this.changeToId( termUri );
Collection onDisease = this.findOntologyTermsUriWithDiseaseId( meshId );
diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/ExpressionExperimentPlatformSwitchService.java b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/ExpressionExperimentPlatformSwitchService.java
index 66773ad296..76c7ae74af 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/ExpressionExperimentPlatformSwitchService.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/ExpressionExperimentPlatformSwitchService.java
@@ -278,6 +278,8 @@ private void cleanupUnused( ExpressionExperiment ee, Collection() );
+ // numberOfSample is updated later when the BAs are populated
if ( series.getSampleCorrespondence().size() == 0 ) {
throw new IllegalArgumentException( "No sample correspondence!" );
@@ -2703,7 +2704,7 @@ private FactorValue findMatchingExperimentalFactorValue( Collection fetchAndLoad( String geoAccession, boolean loadPlatformOnly, boole
void setGeoDomainObjectGenerator( GeoDomainObjectGenerator generator );
+ /**
+ * Load from a SOFT file. This can be used for testing but maybe there are other situations it is useful.
+ *
+ * @param accession e.g GSE1234
+ * @param softFile the full path to the SOFT file. The file name has to be [accession].soft.gz
+ * @return a single experiment.
+ */
+ Collection> loadFromSoftFile( String accession, String softFile, boolean loadPlatformOnly, boolean doSampleMatching, boolean splitByPlatform );
}
\ No newline at end of file
diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/geo/service/GeoServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/geo/service/GeoServiceImpl.java
index 57f19d8912..b99a27d12a 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/geo/service/GeoServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/geo/service/GeoServiceImpl.java
@@ -19,7 +19,6 @@
package ubic.gemma.core.loader.expression.geo.service;
import org.apache.commons.lang3.StringUtils;
-import org.hibernate.cfg.Settings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -28,10 +27,7 @@
import ubic.gemma.core.analysis.report.ExpressionExperimentReportService;
import ubic.gemma.core.annotation.reference.BibliographicReferenceService;
import ubic.gemma.core.loader.entrez.pubmed.PubMedXMLFetcher;
-import ubic.gemma.core.loader.expression.geo.DatasetCombiner;
-import ubic.gemma.core.loader.expression.geo.GeoConverter;
-import ubic.gemma.core.loader.expression.geo.GeoDomainObjectGenerator;
-import ubic.gemma.core.loader.expression.geo.GeoSampleCorrespondence;
+import ubic.gemma.core.loader.expression.geo.*;
import ubic.gemma.core.loader.expression.geo.model.*;
import ubic.gemma.core.loader.util.AlreadyExistsInSystemException;
import ubic.gemma.model.common.auditAndSecurity.eventType.ExpressionExperimentUpdateFromGEOEvent;
@@ -44,7 +40,6 @@
import ubic.gemma.model.expression.designElement.CompositeSequence;
import ubic.gemma.model.expression.experiment.ExpressionExperiment;
import ubic.gemma.model.genome.biosequence.BioSequence;
-import ubic.gemma.persistence.persister.Persister;
import ubic.gemma.persistence.service.ExpressionExperimentPrePersistService;
import ubic.gemma.persistence.service.common.auditAndSecurity.AuditTrailService;
import ubic.gemma.persistence.service.common.description.CharacteristicService;
@@ -53,8 +48,8 @@
import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService;
import ubic.gemma.persistence.service.genome.taxon.TaxonService;
import ubic.gemma.persistence.util.ArrayDesignsForExperimentCache;
-import ubic.gemma.persistence.util.SettingsConfig;
+import java.io.File;
import java.util.*;
/**
@@ -67,7 +62,7 @@ public class GeoServiceImpl extends AbstractGeoService {
private static final String GEO_DB_NAME = "GEO";
- @Value( "${geo.minimumSamplesToLoad}")
+ @Value("${geo.minimumSamplesToLoad}")
private int MINIMUM_SAMPLE_COUNT_TO_LOAD;
private final ArrayDesignReportService arrayDesignReportService;
@@ -389,6 +384,15 @@ public void updateFromGEO( String geoAccession ) {
}
+ @Override
+ @Transactional
+ public Collection> loadFromSoftFile( String accession, String softFile, boolean loadPlatformOnly, boolean doSampleMatching, boolean splitByPlatform ) {
+ File f = new File( softFile );
+ this.setGeoDomainObjectGenerator(
+ new GeoDomainObjectGeneratorLocal( f.getParent() ) );
+ return fetchAndLoad( accession, loadPlatformOnly, doSampleMatching, splitByPlatform );
+ }
+
private void check( Collection result ) {
for ( ExpressionExperiment expressionExperiment : result ) {
this.check( expressionExperiment );
diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/simple/ExperimentalDesignImporterImpl.java b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/simple/ExperimentalDesignImporterImpl.java
index 04ede86afb..47634236f2 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/simple/ExperimentalDesignImporterImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/simple/ExperimentalDesignImporterImpl.java
@@ -368,9 +368,7 @@ private void addFactorValuesToExperimentalFactor( ExperimentalFactor experimenta
ExperimentalDesignImporterImpl.log.debug( "Factor is categorical" );
Statement newVc = Statement.Factory.newInstance();
if ( category != null ) {
- String category2 = category.getCategory();
- assert category2 != null;
- newVc.setCategory( category2 );
+ newVc.setCategory( category.getCategory() );
newVc.setCategoryUri( category.getCategoryUri() );
}
newVc.setValue( value ); // don't have a valueUri at this point
@@ -580,12 +578,12 @@ private Map mapBioMaterialsToNamePossibilities( Collection<
private Characteristic termForCategoryLookup( String category, Collection terms ) {
OntologyTerm t = null;
- String lookup = category.replaceAll( "_", " " ).toLowerCase();
+ String lookup = category.replaceAll( "_", " " );
for ( OntologyTerm to : terms ) {
- if ( to.getLabel().equals( category )
- || to.getLabel().toLowerCase().equals( lookup )
+ if ( category.equalsIgnoreCase( to.getLabel() )
+ || lookup.equalsIgnoreCase( to.getLabel() )
// if EFO is loaded, the "sex" term is actually named "biological sex"
- || ( to.getLabel().equals( "biological sex" ) && lookup.equals( "sex" ) ) ) {
+ || ( "biological sex".equalsIgnoreCase( to.getLabel() ) && "sex".equalsIgnoreCase( lookup ) ) ) {
t = to;
break;
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/ontology/GoMetricImpl.java b/gemma-core/src/main/java/ubic/gemma/core/ontology/GoMetricImpl.java
index ad18c75ab0..2ddbbfadff 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/ontology/GoMetricImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/ontology/GoMetricImpl.java
@@ -19,6 +19,7 @@
package ubic.gemma.core.ontology;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -113,7 +114,7 @@ public Double computeMaxSimilarity( Gene queryGene, Gene targetGene, Map termCountMap, String
int termCount = termCountMap.get( term );
OntologyTerm ont = geneOntologyService.getTerm( term );
+ if ( ont == null ) {
+ GoMetricImpl.log.warn( "No GO term found for: " + term + ", will fallback to zero for the number of children occurrences." );
+ return 0;
+ }
+
Collection children = ont.getChildren( false, partOf );
if ( children.isEmpty() ) {
@@ -397,7 +403,7 @@ private Double checkParents( OntologyTerm ontoM, OntologyTerm ontoC, Map getChildren( Collection terms, boolean di
public Collection getCategoryTerms() {
return categoryTerms.stream()
.map( term -> {
+ String termUri = term.getUri();
+ if ( termUri == null ) {
+ return term; // a free-text category
+ }
if ( experimentalFactorOntologyService.isOntologyLoaded() ) {
- OntologyTerm efoTerm = experimentalFactorOntologyService.getTerm( term.getUri() );
+ OntologyTerm efoTerm = experimentalFactorOntologyService.getTerm( termUri );
if ( efoTerm != null ) {
return efoTerm;
}
@@ -448,7 +452,7 @@ public String getDefinition( String uri ) {
if ( ot != null ) {
for ( AnnotationProperty ann : ot.getAnnotations() ) {
// FIXME: not clear this will work with all ontologies. UBERON, HP, MP, MONDO does it this way.
- if ( ann.getUri().equals( "http://purl.obolibrary.org/obo/IAO_0000115" ) ) {
+ if ( "http://purl.obolibrary.org/obo/IAO_0000115".equals( ann.getUri() ) ) {
return ann.getContents();
}
}
@@ -681,6 +685,10 @@ private Collection findCharacteristicsFromOntology( S
for ( OntologyTerm ontologyTerm : ontologyTerms ) {
// if the ontology term wasnt already found in the database
if ( characteristicFromDatabaseWithValueUri.get( ontologyTerm.getUri() ) == null ) {
+ if ( ontologyTerm.getLabel() == null ) {
+ log.warn( "Term with null label: " + ontologyTerm.getUri() + "; it cannot be converted to a CharacteristicValueObject" );
+ continue;
+ }
CharacteristicValueObject phenotype = new CharacteristicValueObject( ontologyTerm.getLabel().toLowerCase(), ontologyTerm.getUri() );
characteristicsFromOntology.add( phenotype );
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/ontology/providers/GeneOntologyServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/ontology/providers/GeneOntologyServiceImpl.java
index d36278a874..7c4270e35c 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/ontology/providers/GeneOntologyServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/ontology/providers/GeneOntologyServiceImpl.java
@@ -76,6 +76,9 @@ public static String asRegularGoId( OntologyTerm term ) {
if ( term == null )
return null;
String uri = term.getUri();
+ if ( uri == null ) {
+ return null;
+ }
return GeneOntologyServiceImpl.asRegularGoId( uri );
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/search/GeneSetSearchImpl.java b/gemma-core/src/main/java/ubic/gemma/core/search/GeneSetSearchImpl.java
index a10a027c94..4a3e8ed4ea 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/search/GeneSetSearchImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/search/GeneSetSearchImpl.java
@@ -32,6 +32,7 @@
import ubic.gemma.core.genome.gene.GeneSetValueObjectHelper;
import ubic.gemma.core.genome.gene.service.GeneSetService;
import ubic.gemma.core.ontology.providers.GeneOntologyService;
+import ubic.gemma.model.common.description.CharacteristicValueObject;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.Taxon;
import ubic.gemma.model.genome.TaxonValueObject;
@@ -39,7 +40,6 @@
import ubic.gemma.model.genome.gene.GeneSetMember;
import ubic.gemma.model.genome.gene.GeneSetValueObject;
import ubic.gemma.model.genome.gene.GeneValueObject;
-import ubic.gemma.model.common.description.CharacteristicValueObject;
import ubic.gemma.persistence.service.association.Gene2GOAssociationService;
import ubic.gemma.persistence.service.genome.taxon.TaxonService;
import ubic.gemma.persistence.util.EntityUtils;
diff --git a/gemma-core/src/main/java/ubic/gemma/core/util/BuildInfo.java b/gemma-core/src/main/java/ubic/gemma/core/util/BuildInfo.java
index 79170613f3..3faf3023ae 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/util/BuildInfo.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/util/BuildInfo.java
@@ -1,32 +1,41 @@
package ubic.gemma.core.util;
+import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
import org.springframework.format.datetime.DateFormatter;
-import ubic.gemma.persistence.util.Settings;
import javax.annotation.Nullable;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
import java.text.DateFormat;
+import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
+import java.util.Properties;
+@CommonsLog
@Configuration
public class BuildInfo implements InitializingBean {
private static final String MAVEN_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
/**
- * Retrieves the build info using {@link Settings}
- * @deprecated simply autowire this configuration to access build information at runtime
+ * Retrieve build information directly from the classpath.
*/
- @Deprecated
- public static BuildInfo fromSettings() {
- try {
- return new BuildInfo( Settings.getString( "gemma.version" ),
- Settings.getString( "gemma.build.timestamp" ),
- Settings.getString( "gemma.build.gitHash" ) );
- } catch ( Exception e ) {
+ public static BuildInfo fromClasspath() {
+ Properties props = new Properties();
+ try ( InputStream reader = new ClassPathResource( "/ubic/gemma/version.properties" ).getInputStream() ) {
+ props.load( reader );
+ return new BuildInfo( props.getProperty( "gemma.version" ),
+ props.getProperty( "gemma.build.timestamp" ),
+ props.getProperty( "gemma.build.gitHash" ) );
+ } catch ( FileNotFoundException e ) {
+ return new BuildInfo();
+ } catch ( IOException e ) {
throw new RuntimeException( e );
}
}
@@ -44,7 +53,7 @@ public BuildInfo() {
}
- private BuildInfo( String version, String timestampAsString, String gitHash ) throws Exception {
+ private BuildInfo( String version, String timestampAsString, String gitHash ) {
this.version = version;
this.timestampAsString = timestampAsString;
this.gitHash = gitHash;
@@ -52,10 +61,15 @@ private BuildInfo( String version, String timestampAsString, String gitHash ) th
}
@Override
- public void afterPropertiesSet() throws Exception {
+ public void afterPropertiesSet() {
if ( timestampAsString != null ) {
- timestamp = new DateFormatter( MAVEN_DATETIME_PATTERN )
- .parse( timestampAsString, Locale.getDefault() );
+ try {
+ timestamp = new DateFormatter( MAVEN_DATETIME_PATTERN )
+ .parse( timestampAsString, Locale.getDefault() );
+
+ } catch ( ParseException e ) {
+ log.error( "Failed to parse build timestamp.", e );
+ }
}
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/util/DummyMailSender.java b/gemma-core/src/main/java/ubic/gemma/core/util/DummyMailSender.java
index a36a358c60..10411dc818 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/util/DummyMailSender.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/util/DummyMailSender.java
@@ -22,7 +22,7 @@
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
-import ubic.gemma.persistence.util.SpringProfiles;
+import ubic.gemma.persistence.util.EnvironmentProfiles;
/**
* Mock mail sender for testing.
@@ -38,7 +38,7 @@ public class DummyMailSender implements MailSender, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
- if ( environment.acceptsProfiles( SpringProfiles.DEV ) ) {
+ if ( environment.acceptsProfiles( EnvironmentProfiles.DEV ) ) {
log.warn( "Emails will be sent to a dummy mail sender. If this is not intended, activate the 'production' profile by setting -Dspring.profiles.active=production." );
}
}
diff --git a/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationService.java b/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationService.java
index ed5adaf8de..50a2f8ef0c 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationService.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationService.java
@@ -18,6 +18,7 @@
import ubic.gemma.model.expression.bioAssayData.DoubleVectorValueObject;
import ubic.gemma.model.expression.experiment.ExperimentalFactor;
+import javax.annotation.Nullable;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -27,6 +28,18 @@
*/
public interface ExperimentalDesignVisualizationService {
+ /**
+ * Put data vectors in the order you'd want to display the experimental design. This causes the "isReorganized" flag
+ * of the dedVs to be set to true.
+ *
+ * @param dedVs dedVs, already sliced for the subset of samples needed for display (if necessary); will be modified
+ * @param primaryFactor if non-null this factor will be used to order the data, otherwise the first factor will be chosen using built-in heuristics. Set this to ensure that
+ * the data is ordered by the factor you want as in the case of showing DE genes
+ * @return Map of EE ids to "layouts", which are Maps of BioAssays to map of experimental factors to doubles.
+ */
+ Map>> sortVectorDataByDesign(
+ Collection dedVs, @Nullable ExperimentalFactor primaryFactor );
+
/**
* Put data vectors in the order you'd want to display the experimental design. This causes the "isReorganized" flag
* of the dedVs to be set to true.
diff --git a/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationServiceImpl.java
index 9c111d9b9d..4bb11e5cca 100644
--- a/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/core/visualization/ExperimentalDesignVisualizationServiceImpl.java
@@ -24,6 +24,8 @@
import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.commons.math3.analysis.function.Exp;
+import org.apache.log4j.Layout;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ubic.basecode.dataStructure.matrix.DoubleMatrix;
@@ -44,6 +46,7 @@
import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService;
import ubic.gemma.persistence.util.EntityUtils;
+import javax.annotation.Nullable;
import java.awt.*;
import java.io.File;
import java.io.IOException;
@@ -60,10 +63,50 @@
@Component
public class ExperimentalDesignVisualizationServiceImpl implements ExperimentalDesignVisualizationService {
+ class LayoutSelection {
+ private Long experimentId;
+ private Long factorId; // nullable.
+
+ public LayoutSelection( Long experimentId, @Nullable ExperimentalFactor primaryFactor ) {
+ this.experimentId = experimentId;
+
+ if ( primaryFactor != null )
+ this.factorId = primaryFactor.getId();
+ }
+
+ public LayoutSelection( Long experimentId, Long primaryFactorId ) {
+ this.experimentId = experimentId;
+ this.factorId = primaryFactorId;
+ }
+
+ public LayoutSelection( Long experimentId ) {
+ this.experimentId = experimentId;
+ this.factorId = null;
+ }
+
+ public int hashCode() {
+ return Objects.hash( experimentId, factorId );
+ }
+
+ public boolean equals( Object obj ) {
+ if ( this == obj ) {
+ return true;
+ }
+ if ( obj == null ) {
+ return false;
+ }
+ if ( getClass() != obj.getClass() ) {
+ return false;
+ }
+ LayoutSelection other = ( LayoutSelection ) obj;
+ return Objects.equals( experimentId, other.experimentId ) && Objects.equals( factorId, other.factorId );
+ }
+ }
+
/**
* Cache of layouts for experiments, keyed by experiment ID.
*/
- private final Map>> cachedLayouts = new ConcurrentHashMap<>();
+ private final Map>> cachedLayouts = new ConcurrentHashMap<>();
private final Log log = LogFactory.getLog( this.getClass().getName() );
private final ExpressionExperimentService expressionExperimentService;
@@ -75,6 +118,12 @@ public ExperimentalDesignVisualizationServiceImpl( ExpressionExperimentService e
@Override
public Map>> sortVectorDataByDesign(
Collection dedVs ) {
+ return this.sortVectorDataByDesign( dedVs, null );
+ }
+
+ @Override
+ public Map>> sortVectorDataByDesign(
+ Collection dedVs, ExperimentalFactor primaryFactor ) {
//cachedLayouts.clear(); // uncomment FOR DEBUGGING.
@@ -90,9 +139,9 @@ public Map> newOrderingsForBioAssayDimensions = new HashMap<>();
for ( DoubleVectorValueObject vec : dedVs ) {
@@ -105,17 +154,22 @@ public Map> layout = null;
- if ( cachedLayouts.containsKey( vec.getExpressionExperiment().getId() ) ) {
- layout = cachedLayouts.get( vec.getExpressionExperiment().getId() );
- } else if ( vec.getExpressionExperiment().getClass()
+
+ LayoutSelection cacheKey = null;
+
+ if ( vec.getExpressionExperiment().getClass()
.isInstance( ExpressionExperimentSubsetValueObject.class ) ) {
- // subset.
- layout = cachedLayouts.get( ( ( ExpressionExperimentSubsetValueObject ) vec.getExpressionExperiment() )
- .getSourceExperiment() );
+ cacheKey = new LayoutSelection( ( ( ExpressionExperimentSubsetValueObject ) vec.getExpressionExperiment() ).getSourceExperiment(), primaryFactor );
+ } else {
+ cacheKey = new LayoutSelection( vec.getExpressionExperiment().getId(), primaryFactor );
}
+
+ layout = cachedLayouts.get( cacheKey );
+
+
if ( layout == null || layout.isEmpty() ) {
- log.warn( "Did not find cached layout for " + vec.getId() );
+ log.debug( "Did not find cached layout for " + vec.getId() + ( primaryFactor != null ? " PrimaryFactor=" + primaryFactor.getName() : "" ) );
continue;
}
@@ -216,12 +270,11 @@ public Map> extension = this
- .getExperimentalDesignLayout( actualEe, expressionExperimentService.getBioAssayDimensions( actualEe ) );
+ .getExperimentalDesignLayout( actualEe, expressionExperimentService.getBioAssayDimensions( actualEe ), null );
for ( BioAssayValueObject vbaVo : bioAssayDimension.getBioAssays() ) {
assert extension.containsKey( vbaVo );
@@ -313,9 +366,9 @@ private LinkedHashMap> getExperimentalDesignLayout(
ExpressionExperiment e ) {
- if ( cachedLayouts.containsKey( e.getId() ) ) {
- return cachedLayouts.get( e.getId() );
+ if ( cachedLayouts.containsKey( new LayoutSelection( e.getId() ) ) ) {
+ return cachedLayouts.get( new LayoutSelection( e.getId() ) );
}
Collection bds = expressionExperimentService.getBioAssayDimensions( e );
e = this.expressionExperimentService.thawLite( e );
LinkedHashMap> result = this
- .getExperimentalDesignLayout( e, bds );
+ .getExperimentalDesignLayout( e, bds, null );
- cachedLayouts.put( e.getId(), result );
+ cachedLayouts.put( new LayoutSelection( e.getId() ), result );
return result;
}
@@ -357,11 +410,12 @@ private LinkedHashMap> getExperimentalDesignLayout(
- BioAssaySet experiment, Collection bds ) {
+ BioAssaySet experiment, Collection bds, ExperimentalFactor primaryFactor ) {
LinkedHashMap> result = new LinkedHashMap<>();
@@ -375,7 +429,7 @@ private LinkedHashMap bms = ExpressionDataMatrixColumnSort.orderByExperimentalDesign( mat );
+ List bms = ExpressionDataMatrixColumnSort.orderByExperimentalDesign( mat, primaryFactor );
Map fvV = new HashMap<>();
@@ -433,22 +487,22 @@ private LinkedHashMap alreadyFilled = new HashSet<>();
-
if ( expressionExperiment.getRawExpressionDataVectors().isEmpty() ) {
AbstractPersister.log.debug( "Filling in bioassays" );
for ( BioAssay bioAssay : expressionExperiment.getBioAssays() ) {
this.fillInBioAssayAssociations( bioAssay, caches );
- alreadyFilled.add( bioAssay );
}
} else {
AbstractPersister.log.debug( "Filling in bioassays via data vectors" ); // usual case.
+ Set alreadyFilled;
alreadyFilled = this.fillInExpressionExperimentDataVectorAssociations( expressionExperiment, caches );
expressionExperiment.setBioAssays( alreadyFilled );
+ expressionExperiment.setNumberOfSamples( alreadyFilled.size() );
}
}
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/AbstractQueryFilteringVoEnabledDao.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/AbstractQueryFilteringVoEnabledDao.java
index 2276f3be65..0e2784ffe4 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/AbstractQueryFilteringVoEnabledDao.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/AbstractQueryFilteringVoEnabledDao.java
@@ -15,6 +15,8 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import static java.util.Objects.requireNonNull;
+
/**
* Partial implementation of {@link FilteringVoEnabledDao} based on the Hibernate {@link Query} API.
*
@@ -343,7 +345,8 @@ private Slice doLoadValueObjectsWithCache( @Nullable Filters filters, @Nulla
private long doCountWithCache( @Nullable Filters filters, boolean cacheable ) {
StopWatch timer = StopWatch.createStarted();
try {
- return ( Long ) this.getFilteringCountQuery( filters ).setCacheable( cacheable ).uniqueResult();
+ return ( Long ) requireNonNull( this.getFilteringCountQuery( filters ).setCacheable( cacheable ).uniqueResult(),
+ String.format( "Counting query for %s returned null.", elementClass.getName() ) );
} finally {
timer.stop();
if ( timer.getTime( TimeUnit.MILLISECONDS ) > REPORT_SLOW_QUERY_AFTER_MS ) {
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtil.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtil.java
index dfbbaaf2cb..e940364a1d 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtil.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtil.java
@@ -20,8 +20,6 @@
import org.springframework.security.access.annotation.Secured;
-import java.nio.file.Path;
-
/**
* @author paul
*/
@@ -67,6 +65,15 @@ public interface TableMaintenanceUtil {
@Secured({ "GROUP_AGENT" })
int updateExpressionExperiment2CharacteristicEntries();
+ /**
+ * Update a specific level of the {@code EXPRESSION_EXPERIMENT2CHARACTERISTIC} table.
+ * @param level the level to update which is either {@link ubic.gemma.model.expression.experiment.ExpressionExperiment},
+ * {@link ubic.gemma.model.expression.biomaterial.BioMaterial} or {@link ubic.gemma.model.expression.experiment.ExperimentalDesign}
+ * @return the number of records that were created or updated
+ */
+ @Secured({ "GROUP_AGENT" })
+ int updateExpressionExperiment2CharacteristicEntries( Class> level );
+
/**
* Update the {@code EXPRESSION_EXPERIMENT2_ARRAY_DESIGN} table.
* @return the number of records that were created or updated
@@ -74,9 +81,6 @@ public interface TableMaintenanceUtil {
@Secured({ "GROUP_AGENT" })
int updateExpressionExperiment2ArrayDesignEntries();
- @Secured({ "GROUP_ADMIN" })
- void setGene2CsInfoPath( Path gene2CsInfoPath );
-
// for tests only, to keep from getting emails.
@Secured({ "GROUP_ADMIN" })
void disableEmail();
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtilImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtilImpl.java
index 28328505a5..b8f0fe281a 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtilImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/TableMaintenanceUtilImpl.java
@@ -26,6 +26,7 @@
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -43,7 +44,6 @@
import ubic.gemma.persistence.service.common.description.ExternalDatabaseService;
import ubic.gemma.persistence.service.genome.GeneDao;
import ubic.gemma.persistence.util.MailEngine;
-import ubic.gemma.persistence.util.Settings;
import javax.annotation.Nullable;
import java.io.IOException;
@@ -52,7 +52,6 @@
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
@@ -90,24 +89,25 @@ public class TableMaintenanceUtilImpl implements TableMaintenanceUtil {
+ "and AOI.OBJECT_ID = I.ID "
+ "and ACE.SID_FK = (select ACLSID.ID from ACLSID where ACLSID.GRANTED_AUTHORITY = 'IS_AUTHENTICATED_ANONYMOUSLY') "
+ "group by AOI.ID), 0)";
- /**
- * Query used to repopulate the EXPRESSION_EXPERIMENT2CHARACTERISTIC table.
- */
- private static final String E2C_QUERY =
- "insert into EXPRESSION_EXPERIMENT2CHARACTERISTIC (ID, NAME, DESCRIPTION, CATEGORY, CATEGORY_URI, `VALUE`, VALUE_URI, ORIGINAL_VALUE, EVIDENCE_CODE, EXPRESSION_EXPERIMENT_FK, ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK, LEVEL) "
- + "select C.ID, C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(:eeClass as char(256)) "
+
+ private static final String EE2C_EE_QUERY =
+ "select MIN(C.ID), C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(? as char(256)) "
+ "from INVESTIGATION I "
+ "join CHARACTERISTIC C on I.ID = C.INVESTIGATION_FK "
+ "where I.class = 'ExpressionExperiment' "
- + "union "
- + "select C.ID, C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(:bmClass as char(255)) "
+ + "group by I.ID, COALESCE(C.CATEGORY_URI, C.CATEGORY), COALESCE(C.VALUE_URI, C.`VALUE`)";
+
+ private static final String EE2C_BM_QUERY =
+ "select MIN(C.ID), C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(? as char(255)) "
+ "from INVESTIGATION I "
+ "join BIO_ASSAY BA on I.ID = BA.EXPRESSION_EXPERIMENT_FK "
+ "join BIO_MATERIAL BM on BA.SAMPLE_USED_FK = BM.ID "
+ "join CHARACTERISTIC C on BM.ID = C.BIO_MATERIAL_FK "
+ "where I.class = 'ExpressionExperiment' "
- + "union "
- + "select C.ID, C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(:edClass as char(255)) "
+ + "group by I.ID, COALESCE(C.CATEGORY_URI, C.CATEGORY), COALESCE(C.VALUE_URI, C.`VALUE`)";
+
+ private static final String EE2C_ED_QUERY =
+ "select MIN(C.ID), C.NAME, C.DESCRIPTION, C.CATEGORY, C.CATEGORY_URI, C.`VALUE`, C.VALUE_URI, C.ORIGINAL_VALUE, C.EVIDENCE_CODE, I.ID, (" + SELECT_ANONYMOUS_MASK + "), cast(? as char(255)) "
+ "from INVESTIGATION I "
+ "join EXPERIMENTAL_DESIGN on I.EXPERIMENTAL_DESIGN_FK = EXPERIMENTAL_DESIGN.ID "
+ "join EXPERIMENTAL_FACTOR EF on EXPERIMENTAL_DESIGN.ID = EF.EXPERIMENTAL_DESIGN_FK "
@@ -115,21 +115,24 @@ public class TableMaintenanceUtilImpl implements TableMaintenanceUtil {
+ "join CHARACTERISTIC C on FV.ID = C.FACTOR_VALUE_FK "
// remove C.class = 'Statement' once the old-style characteristics are removed (see https://github.com/PavlidisLab/Gemma/issues/929 for details)
+ "where I.class = 'ExpressionExperiment' and C.class = 'Statement' "
- + "on duplicate key update NAME = VALUES(NAME), DESCRIPTION = VALUES(DESCRIPTION), CATEGORY = VALUES(CATEGORY), CATEGORY_URI = VALUES(CATEGORY_URI), `VALUE` = VALUES(`VALUE`), VALUE_URI = VALUES(VALUE_URI), ORIGINAL_VALUE = VALUES(ORIGINAL_VALUE), EVIDENCE_CODE = VALUES(EVIDENCE_CODE), ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK = VALUES(ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK)";
+ + "group by I.ID, COALESCE(C.CATEGORY_URI, C.CATEGORY), COALESCE(C.VALUE_URI, C.`VALUE`)";
private static final String EE2AD_QUERY = "insert into EXPRESSION_EXPERIMENT2ARRAY_DESIGN (EXPRESSION_EXPERIMENT_FK, ARRAY_DESIGN_FK, IS_ORIGINAL_PLATFORM, ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK) "
+ "select I.ID, AD.ID, FALSE, (" + SELECT_ANONYMOUS_MASK + ") from INVESTIGATION I "
+ "join BIO_ASSAY BA on I.ID = BA.EXPRESSION_EXPERIMENT_FK "
+ "join ARRAY_DESIGN AD on BA.ARRAY_DESIGN_USED_FK = AD.ID "
+ + "where I.class = 'ExpressionExperiment' "
+ "group by I.ID, AD.ID "
+ "union "
+ "select I.ID, AD.ID, TRUE, (" + SELECT_ANONYMOUS_MASK + ") from INVESTIGATION I "
+ "join BIO_ASSAY BA on I.ID = BA.EXPRESSION_EXPERIMENT_FK "
+ "join ARRAY_DESIGN AD on BA.ORIGINAL_PLATFORM_FK = AD.ID "
+ + "where I.class = 'ExpressionExperiment' "
+ "group by I.ID, AD.ID "
+ "on duplicate key update ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK = VALUES(ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK)";
- private static final Path DEFAULT_GENE2CS_INFO_PATH = Paths.get( Settings.getString( "gemma.appdata.home" ), "DbReports", "gene2cs.info" );
+
private static final Log log = LogFactory.getLog( TableMaintenanceUtil.class.getName() );
+
@Autowired
private AuditEventService auditEventService;
@@ -142,7 +145,12 @@ public class TableMaintenanceUtilImpl implements TableMaintenanceUtil {
@Autowired
private SessionFactory sessionFactory;
- private Path gene2CsInfoPath = DEFAULT_GENE2CS_INFO_PATH;
+ @Value("${gemma.gene2cs.path}")
+ private Path gene2CsInfoPath;
+
+ @Value("${gemma.admin.email}")
+ private String adminEmailAddress;
+
private boolean sendEmail = true;
@Override
@@ -217,16 +225,52 @@ public void updateGene2CsEntries() {
@Timed
public int updateExpressionExperiment2CharacteristicEntries() {
log.info( "Updating the EXPRESSION_EXPERIMENT2CHARACTERISTIC table..." );
- int updated = sessionFactory.getCurrentSession().createSQLQuery( E2C_QUERY )
+ int updated = sessionFactory.getCurrentSession()
+ .createSQLQuery(
+ "insert into EXPRESSION_EXPERIMENT2CHARACTERISTIC (ID, NAME, DESCRIPTION, CATEGORY, CATEGORY_URI, `VALUE`, VALUE_URI, ORIGINAL_VALUE, EVIDENCE_CODE, EXPRESSION_EXPERIMENT_FK, ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK, LEVEL) "
+ + EE2C_EE_QUERY
+ + " union "
+ + EE2C_BM_QUERY
+ + " union "
+ + EE2C_ED_QUERY + " "
+ + "on duplicate key update NAME = VALUES(NAME), DESCRIPTION = VALUES(DESCRIPTION), CATEGORY = VALUES(CATEGORY), CATEGORY_URI = VALUES(CATEGORY_URI), `VALUE` = VALUES(`VALUE`), VALUE_URI = VALUES(VALUE_URI), ORIGINAL_VALUE = VALUES(ORIGINAL_VALUE), EVIDENCE_CODE = VALUES(EVIDENCE_CODE), ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK = VALUES(ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK), LEVEL = VALUES(LEVEL)" )
.addSynchronizedQuerySpace( EE2C_QUERY_SPACE )
- .setParameter( "eeClass", ExpressionExperiment.class )
- .setParameter( "bmClass", BioMaterial.class )
- .setParameter( "edClass", ExperimentalDesign.class )
+ .setParameter( 0, ExpressionExperiment.class )
+ .setParameter( 1, BioMaterial.class )
+ .setParameter( 2, ExperimentalDesign.class )
.executeUpdate();
log.info( String.format( "Done updating the EXPRESSION_EXPERIMENT2CHARACTERISTIC table; %d entries were updated.", updated ) );
return updated;
}
+ @Override
+ @Timed
+ @Transactional
+ public int updateExpressionExperiment2CharacteristicEntries( Class> level ) {
+ String query;
+ if ( level.equals( ExpressionExperiment.class ) ) {
+ query = EE2C_EE_QUERY;
+ } else if ( level.equals( BioMaterial.class ) ) {
+ query = EE2C_BM_QUERY;
+ } else if ( level.equals( ExperimentalDesign.class ) ) {
+ query = EE2C_ED_QUERY;
+ } else {
+ throw new IllegalArgumentException( "Level must be one of ExpressionExperiment.class, BioMaterial.class or ExperimentalDesign.class." );
+ }
+ log.info( "Updating the EXPRESSION_EXPERIMENT2CHARACTERISTIC table at level " + level + "..." );
+ int updated = sessionFactory.getCurrentSession()
+ .createSQLQuery(
+ "insert into EXPRESSION_EXPERIMENT2CHARACTERISTIC (ID, NAME, DESCRIPTION, CATEGORY, CATEGORY_URI, `VALUE`, VALUE_URI, ORIGINAL_VALUE, EVIDENCE_CODE, EXPRESSION_EXPERIMENT_FK, ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK, LEVEL) "
+ + query + " "
+ + "on duplicate key update NAME = VALUES(NAME), DESCRIPTION = VALUES(DESCRIPTION), CATEGORY = VALUES(CATEGORY), CATEGORY_URI = VALUES(CATEGORY_URI), `VALUE` = VALUES(`VALUE`), VALUE_URI = VALUES(VALUE_URI), ORIGINAL_VALUE = VALUES(ORIGINAL_VALUE), EVIDENCE_CODE = VALUES(EVIDENCE_CODE), ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK = VALUES(ACL_IS_AUTHENTICATED_ANONYMOUSLY_MASK), LEVEL = VALUES(LEVEL)" )
+ .addSynchronizedQuerySpace( EE2C_QUERY_SPACE )
+ .setParameter( 0, level )
+ .executeUpdate();
+ log.info( String.format( "Done updating the EXPRESSION_EXPERIMENT2CHARACTERISTIC table at %s level; %d entries were updated.",
+ level.getSimpleName(), updated ) );
+ return updated;
+ }
+
@Override
@Transactional
public int updateExpressionExperiment2ArrayDesignEntries() {
@@ -238,14 +282,6 @@ public int updateExpressionExperiment2ArrayDesignEntries() {
return updated;
}
- /**
- * For use in tests.
- */
- @Override
- public void setGene2CsInfoPath( Path gene2CsInfoPath ) {
- this.gene2CsInfoPath = gene2CsInfoPath;
- }
-
/**
* For use in tests.
*/
@@ -289,7 +325,6 @@ private void sendEmail( Gene2CsStatus results ) {
if ( !sendEmail )
return;
SimpleMailMessage msg = new SimpleMailMessage();
- String adminEmailAddress = Settings.getAdminEmailAddress();
if ( StringUtils.isBlank( adminEmailAddress ) ) {
TableMaintenanceUtilImpl.log
.warn( "No administrator email address could be found, so gene2cs status email will not be sent." );
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDao.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDao.java
index 403ab86181..97935314af 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDao.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDao.java
@@ -56,10 +56,15 @@ Collection find( Gene gene, ExpressionAnalysisRe
double threshold );
/**
- * @return analyses associated with the factor, either through the subsetfactor or as factors for resultsets.
+ * Retrieve analyses associated with the factor, either through the subset factor or as factors for result sets.
*/
Collection findByFactor( ExperimentalFactor ef );
+ /**
+ * @see #findByFactor(ExperimentalFactor)
+ */
+ Collection findByFactors( Collection experimentalFactors );
+
Map> findByExperimentIds( Collection investigationIds );
Collection findExperimentsWithAnalyses( Gene gene );
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDaoImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDaoImpl.java
index a4ee6d20c2..aa49bfdc75 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDaoImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisDaoImpl.java
@@ -291,24 +291,57 @@ public Collection find( Gene gene, ExpressionAna
@Override
public Collection findByFactor( ExperimentalFactor ef ) {
+ Set results = new HashSet<>();
// subset factorValues factors.
- @SuppressWarnings("unchecked")
- Collection result = this.getSessionFactory().getCurrentSession()
- .createQuery( "select distinct a from DifferentialExpressionAnalysis a join a.subsetFactorValue ssf"
- + " join ssf.experimentalFactor efa where efa = :ef " )
+ //noinspection unchecked
+ results.addAll( this.getSessionFactory().getCurrentSession()
+ .createQuery( "select distinct a from DifferentialExpressionAnalysis a "
+ + "join a.subsetFactorValue ssf "
+ + "where ssf.experimentalFactor = :ef" )
.setParameter( "ef", ef )
- .list();
+ .list() );
// factors used in the analysis.
//noinspection unchecked
- result.addAll( this.getSessionFactory().getCurrentSession()
- .createQuery( "select distinct a from DifferentialExpressionAnalysis a join a.resultSets rs"
- + " left join rs.baselineGroup bg join rs.experimentalFactors efa where efa = :ef " )
+ results.addAll( this.getSessionFactory().getCurrentSession()
+ .createQuery( "select distinct a from DifferentialExpressionAnalysis a "
+ + "join a.resultSets rs "
+ + "join rs.experimentalFactors efa "
+ + "where efa = :ef" )
.setParameter( "ef", ef )
.list() );
- return result;
+ return results;
+ }
+
+ @Override
+ public Collection findByFactors( Collection experimentalFactors ) {
+ if ( experimentalFactors.isEmpty() ) {
+ return Collections.emptySet();
+ }
+
+ Set results = new HashSet<>();
+ // subset factorValues factors.
+ //noinspection unchecked
+ results.addAll( this.getSessionFactory().getCurrentSession()
+ .createQuery( "select distinct a from DifferentialExpressionAnalysis a "
+ + "join a.subsetFactorValue ssf "
+ + "where ssf.experimentalFactor in :efs" )
+ .setParameterList( "efs", experimentalFactors )
+ .list() );
+
+ // factors used in the analysis
+ //noinspection unchecked
+ results.addAll( this.getSessionFactory().getCurrentSession()
+ .createQuery( "select distinct a from DifferentialExpressionAnalysis a "
+ + "join a.resultSets rs "
+ + "join rs.experimentalFactors efa "
+ + "where efa in :efs" )
+ .setParameterList( "efs", experimentalFactors )
+ .list() );
+
+ return results;
}
@Override
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisService.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisService.java
index 63066df668..70f01865e5 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisService.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisService.java
@@ -133,4 +133,11 @@ Map> getAnalysesByExperiment(
Collection ids, int offset, int limit );
+ /**
+ * Remove analyses using the given factor.
+ * @return the number of analysis removed
+ */
+ int removeForExperimentalFactor( ExperimentalFactor experimentalFactor );
+
+ int removeForExperimentalFactors( Collection experimentalFactors );
}
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisServiceImpl.java
index f3b6ab521e..a964eb42e2 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisServiceImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionAnalysisServiceImpl.java
@@ -253,6 +253,22 @@ public void removeForExperiment( BioAssaySet ee ) {
this.remove( diffAnalyses );
}
+ @Override
+ @Transactional
+ public int removeForExperimentalFactor( ExperimentalFactor experimentalFactor ) {
+ Collection found = differentialExpressionAnalysisDao.findByFactor( experimentalFactor );
+ this.remove( found );
+ return found.size();
+ }
+
+ @Override
+ @Transactional
+ public int removeForExperimentalFactors( Collection experimentalFactors ) {
+ Collection found = differentialExpressionAnalysisDao.findByFactors( experimentalFactors );
+ this.remove( found );
+ return found.size();
+ }
+
@Override
@Transactional(readOnly = true)
public Collection findByExperiment( BioAssaySet experiment ) {
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDao.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDao.java
index 409d58ab26..e89cac8dfa 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDao.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDao.java
@@ -19,10 +19,8 @@
package ubic.gemma.persistence.service.analysis.expression.diff;
import ubic.basecode.math.distribution.Histogram;
-import ubic.gemma.model.analysis.expression.diff.ExpressionAnalysisResultSet;
import ubic.gemma.model.analysis.expression.diff.*;
import ubic.gemma.model.expression.experiment.BioAssaySet;
-import ubic.gemma.model.expression.experiment.ExperimentalFactor;
import ubic.gemma.model.expression.experiment.ExpressionExperimentValueObject;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.persistence.service.BaseDao;
@@ -39,93 +37,52 @@ public interface DifferentialExpressionResultDao extends BaseDao> find( Gene gene,
+ Map> findByGeneAndExperimentAnalyzed( Gene gene,
Collection experimentsAnalyzed, double threshold, int limit );
/**
* Given a list of experiments and a threshold value finds all the probes that met the cut off in the given
* experiments
- *
- * @param experimentsAnalyzed ees
- * @param threshold threshold
- * @param limit limit
- * @return map to diff exp VOs
*/
- Map> find(
+ Map> findByExperimentAnalyzed(
Collection experimentsAnalyzed, double threshold, int limit );
/**
- * @param gene gene
- * @return a map of a collection of {@link DifferentialExpressionAnalysisResult}s keyed by {@link BioAssaySet}.
+ * Find differential expression results for a given gene, grouped by experiment.
+ * @return a map of a collection of {@link DifferentialExpressionAnalysisResult}s keyed by {@link BioAssaySet}.
*/
- Map> find( Gene gene );
+ Map> findByGene( Gene gene );
/**
- * @param gene gene
- * @param experimentsAnalyzed ees
- * @return a map of a collection of {@link DifferentialExpressionAnalysisResult}s keyed by
+ * Find differential expression results for a given gene and set of experiments, grouped by experiment.
+ * @return a map of a collection of {@link DifferentialExpressionAnalysisResult}s keyed by
* {@link BioAssaySet}.
*/
- Map> find( Gene gene,
+ Map> findByGeneAndExperimentAnalyzed( Gene gene,
Collection experimentsAnalyzed );
/**
- * @param geneIds gene ids
- * @param resultSets result sets
- * @return map of resultSetId to map of gene to DiffExprGeneSearchResult
+ * @return map of resultSetId to map of gene to DiffExprGeneSearchResult
*/
Map> findDiffExAnalysisResultIdsInResultSets(
Collection resultSets, Collection geneIds );
- List findGeneInResultSets( Gene gene, ExpressionAnalysisResultSet resultSet,
- Collection arrayDesignIds, int limit );
-
List findInResultSet( ExpressionAnalysisResultSet resultSet, Double threshold,
int maxResultsToReturn, int minNumberOfResults );
- /**
- * Given a list of result sets finds the diff expression results that met the given threshold
- *
- * @param resultsAnalyzed resultsAnalyzed
- * @param threshold threshold
- * @param limit limit
- * @return map to diff exp VOs
- */
- Map> findInResultSets(
- Collection resultsAnalyzed, double threshold, int limit );
-
- DifferentialExpressionAnalysis getAnalysis( ExpressionAnalysisResultSet rs );
-
- Collection getExperimentalFactors(
- DifferentialExpressionAnalysisResult differentialExpressionAnalysisResult );
-
- Map> getExperimentalFactors(
- Collection differentialExpressionAnalysisResults );
-
Map loadContrastDetailsForResults( Collection ids );
- void thaw( Collection results );
-
- void thaw( final DifferentialExpressionAnalysisResult result );
-
/**
* Find differential expression for a gene, exceeding a given significance level (using the corrected pvalue field)
*
* @param gene gene
* @param threshold threshold
* @param limit limit
- * @return map to diff exp VOs
+ * @return map to diff exp VOs
*/
Map> find( Gene gene, double threshold,
int limit );
Histogram loadPvalueDistribution( Long resultSetId );
-
}
diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDaoImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDaoImpl.java
index 607e529f43..209562d31f 100644
--- a/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDaoImpl.java
+++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/analysis/expression/diff/DifferentialExpressionResultDaoImpl.java
@@ -21,21 +21,22 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.hibernate.*;
-import org.hibernate.type.StandardBasicTypes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
+import org.springframework.util.Assert;
import ubic.basecode.io.ByteArrayConverter;
import ubic.basecode.math.distribution.Histogram;
import ubic.basecode.util.BatchIterator;
import ubic.basecode.util.SQLUtils;
import ubic.gemma.model.analysis.expression.diff.*;
-import ubic.gemma.model.expression.designElement.CompositeSequence;
-import ubic.gemma.model.expression.experiment.*;
+import ubic.gemma.model.expression.experiment.BioAssaySet;
+import ubic.gemma.model.expression.experiment.ExperimentalFactor;
+import ubic.gemma.model.expression.experiment.ExperimentalFactorValueObject;
+import ubic.gemma.model.expression.experiment.ExpressionExperimentValueObject;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.gene.GeneValueObject;
import ubic.gemma.persistence.service.AbstractDao;
import ubic.gemma.persistence.util.CommonQueries;
-import ubic.gemma.persistence.util.EntityUtils;
import ubic.gemma.persistence.util.TaskCancelledException;
import java.math.BigInteger;
@@ -53,61 +54,15 @@ public class DifferentialExpressionResultDaoImpl extends AbstractDao> find( Gene gene,
+ public Map> findByGeneAndExperimentAnalyzed( Gene gene,
Collection experimentsAnalyzed, double threshold, int limit ) {
-
- StopWatch timer = new StopWatch();
- timer.start();
- String qs = DifferentialExpressionResultDaoImpl.fetchResultsByGeneAndExperimentsQuery
- + " and r.correctedPvalue < :threshold";
-
- if ( limit > 0 ) {
- qs += " order by r.correctedPvalue";
- }
-
- Map> results = new HashMap<>();
-
- if ( experimentsAnalyzed.size() == 0 ) {
- return results;
+ if ( experimentsAnalyzed.isEmpty() ) {
+ return Collections.emptyMap();
}
+ StopWatch timer = StopWatch.createStarted();
List> qResult = getSessionFactory().getCurrentSession()
- .createQuery( qs )
+ .createQuery( DIFF_EX_RESULTS_BY_GENE_QUERY + " and e.id in (:experimentAnalyzed)"
+ + ( limit > 0 ? " order by r.correctedPvalue" : "" ) )
.setParameter( "gene", gene )
.setParameterList( "experimentsAnalyzed", experimentsAnalyzed )
.setParameter( "threshold", threshold )
@@ -158,142 +102,98 @@ public Map() );
- }
-
- results.get( ee ).add( new DifferentialExpressionValueObject( probeResult ) );
- }
-
- AbstractDao.log
- .warn( "Num experiments with probe analysis results (with limit = " + limit + ") : " + results.size()
- + ". Number of probes returned in total: " + qResult.size() );
+ Map> results = groupDiffExResultVos( qResult );
+ AbstractDao.log.info( String.format( "Num experiments with probe analysis results (with limit = %d) : %d. Number of probes returned in total: %d",
+ limit, results.size(), qResult.size() ) );
timer.stop();
if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
+ AbstractDao.log.warn( "Diff ex results: " + timer.getTime() + " ms" );
}
return results;
}
@Override
- public Map> find(
+ public Map> findByExperimentAnalyzed(
Collection experiments, double qvalueThreshold, int limit ) {
-
- Map> results = new HashMap<>();
-
- if ( experiments.size() == 0 ) {
- return results;
+ if ( experiments.isEmpty() ) {
+ return Collections.emptyMap();
}
-
- StopWatch timer = new StopWatch();
- timer.start();
-
+ StopWatch timer = StopWatch.createStarted();
List> qResult = getSessionFactory().getCurrentSession()
- .createQuery( DifferentialExpressionResultDaoImpl.fetchResultsByExperimentsQuery )
+ .createQuery( "select e, r from DifferentialExpressionAnalysis a "
+ + "join a.experimentAnalyzed e "
+ + "join a.resultSets rs join rs.results r "
+ + "where e.id in (:experimentsAnalyzed) and r.correctedPvalue < :threshold"
+ + ( limit > 0 ? " order by r.correctedPvalue" : "" ) )
.setParameterList( "experimentsAnalyzed", experiments )
.setParameter( "threshold", qvalueThreshold )
.setMaxResults( limit )
.setCacheable( true )
.setCacheRegion( "diffExResult" )
.list();
-
- for ( Object o : qResult ) {
-
- Object[] oa = ( Object[] ) o;
- DifferentialExpressionAnalysisResult probeResult = ( DifferentialExpressionAnalysisResult ) oa[1];
- ExpressionExperimentValueObject eevo = ( ( BioAssaySet ) oa[0] ).createValueObject();
- if ( !results.containsKey( eevo ) ) {
- results.put( eevo, new ArrayList() );
+ try {
+ return groupDiffExResultVos( qResult );
+ } finally {
+ timer.stop();
+ if ( timer.getTime() > 1000 ) {
+ AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
}
-
- results.get( eevo ).add( new DifferentialExpressionValueObject( probeResult ) );
- }
-
- timer.stop();
- if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
}
-
- return results;
}
@Override
- public Map> find( Gene gene ) {
- StopWatch timer = new StopWatch();
- timer.start();
- Map> results = new HashMap<>();
- if ( gene == null )
- return results;
-
- List> qResult = getSessionFactory().getCurrentSession().createQuery( DifferentialExpressionResultDaoImpl.fetchResultsByGene )
+ public Map> findByGene( Gene gene ) {
+ Assert.notNull( gene );
+ StopWatch timer = StopWatch.createStarted();
+ List> qResult = getSessionFactory().getCurrentSession()
+ .createQuery( DIFF_EX_RESULTS_BY_GENE_QUERY )
.setParameter( "gene", gene )
.setCacheable( true )
.list();
-
- for ( Object o : qResult ) {
-
- Object[] oa = ( Object[] ) o;
- ExpressionExperimentValueObject ee = ( ( BioAssaySet ) oa[0] ).createValueObject();
- DifferentialExpressionValueObject probeResult = new DifferentialExpressionValueObject(
- ( DifferentialExpressionAnalysisResult ) oa[1] );
-
- if ( !results.containsKey( ee ) ) {
- results.put( ee, new ArrayList() );
+ try {
+ return groupDiffExResultVos( qResult );
+ } finally {
+ timer.stop();
+ if ( timer.getTime() > 1000 ) {
+ AbstractDao.log.warn( "Diff ex results: " + timer.getTime() + " ms" );
}
-
- results.get( ee ).add( probeResult );
- }
- timer.stop();
- if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
}
- return results;
}
@Override
- public Map> find( Gene gene,
+ public Map> findByGeneAndExperimentAnalyzed( Gene gene,
Collection experimentsAnalyzed ) {
-
- Map> results = new HashMap<>();
-
- if ( experimentsAnalyzed.size() == 0 ) {
- return results;
+ Assert.notNull( gene );
+ if ( experimentsAnalyzed.isEmpty() ) {
+ return Collections.emptyMap();
}
-
- StopWatch timer = new StopWatch();
- timer.start();
-
+ StopWatch timer = StopWatch.createStarted();
List> qResult = this.getSessionFactory().getCurrentSession()
- .createQuery( DifferentialExpressionResultDaoImpl.fetchResultsByGeneAndExperimentsQuery )
+ .createQuery( DIFF_EX_RESULTS_BY_GENE_QUERY + " and e.id in (:experimentsAnalyzed)" )
.setParameter( "gene", gene )
.setParameterList( "experimentsAnalyzed", experimentsAnalyzed )
.list();
+ try {
+ return groupDiffExResultVos( qResult );
+ } finally {
+ timer.stop();
+ if ( timer.getTime() > 1000 ) {
+ AbstractDao.log.warn( "Diff ex results: " + timer.getTime() + " ms" );
+ }
+ }
+ }
+ private Map> groupDiffExResultVos( List> qResult ) {
+ Map> results = new HashMap<>();
for ( Object o : qResult ) {
-
Object[] oa = ( Object[] ) o;
- ExpressionExperimentValueObject ee = new ExpressionExperimentValueObject( ( ExpressionExperiment ) oa[0] );
- DifferentialExpressionValueObject probeResult = new DifferentialExpressionValueObject(
- ( DifferentialExpressionAnalysisResult ) oa[1] );
- probeResult.setExpressionExperiment( ee );
-
- if ( !results.containsKey( ee ) ) {
- results.put( ee, new ArrayList() );
- }
-
- results.get( ee ).add( probeResult );
- }
- timer.stop();
- if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
+ ExpressionExperimentValueObject ee = ( ( BioAssaySet ) oa[0] ).createValueObject();
+ DifferentialExpressionAnalysisResult dear = ( DifferentialExpressionAnalysisResult ) oa[1];
+ Hibernate.initialize( dear.getProbe() );
+ DifferentialExpressionValueObject probeResult = new DifferentialExpressionValueObject( dear );
+ results.computeIfAbsent( ee, k -> new ArrayList<>() ).add( probeResult );
}
return results;
}
@@ -331,8 +231,11 @@ public Map> findDiffExAnalysisResultId
assert !resultSetsNeeded.isEmpty();
- org.hibernate.SQLQuery queryObject = session.createSQLQuery(
- DifferentialExpressionResultDaoImpl.fetchBatchDifferentialExpressionAnalysisResultsByResultSetsAndGeneQuery );
+ SQLQuery queryObject = session.createSQLQuery(
+ "SELECT dear.PROBE_FK, dear.ID,"
+ + " dear.RESULT_SET_FK, dear.CORRECTED_PVALUE, dear.PVALUE "
+ + " FROM DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT dear FORCE INDEX (probeResultSets) WHERE dear.RESULT_SET_FK IN (:rs_ids) AND "
+ + " dear.PROBE_FK IN (:probe_ids) " );
/*
* These values have been tweaked to probe for performance issues.
@@ -352,7 +255,7 @@ public Map> findDiffExAnalysisResultId
+ " resultSets; batch size=" + geneBatchSize );
}
- final int numResultSetBatches = ( int ) Math.ceil( resultSetsNeeded.size() / resultSetBatchSize );
+ final int numResultSetBatches = ( int ) Math.ceil( ( double ) resultSetsNeeded.size() / ( double ) resultSetBatchSize );
queryObject.setFlushMode( FlushMode.MANUAL );
@@ -382,7 +285,7 @@ public Map> findDiffExAnalysisResultId
queryObject.setParameterList( "rs_ids", resultSetIdBatch );
int numGeneBatchesDone = 0;
- final int numGeneBatches = ( int ) Math.ceil( cs2GeneIdMap.size() / geneBatchSize );
+ final int numGeneBatches = ( int ) Math.ceil( ( double ) cs2GeneIdMap.size() / ( double ) geneBatchSize );
StopWatch innerQt = new StopWatch();
@@ -478,65 +381,25 @@ public Map> findDiffExAnalysisResultId
return results;
}
- @Override
- public List findGeneInResultSets( Gene gene, ExpressionAnalysisResultSet resultSet,
- Collection arrayDesignIds, int limit ) {
-
- StopWatch timer = new StopWatch();
- timer.start();
-
- List results;
-
- Session session = this.getSessionFactory().getCurrentSession();
- org.hibernate.SQLQuery queryObject = session
- .createSQLQuery( DifferentialExpressionResultDaoImpl.fetchResultsByResultSetAndGeneQuery );
-
- queryObject.setLong( "gene_id", gene.getId() );
- queryObject.setLong( "rs_id", resultSet.getId() );
-
- queryObject.setMaxResults( limit );
-
- queryObject.addScalar( "CORRECTED_PVALUE", StandardBasicTypes.DOUBLE );
- //noinspection unchecked
- results = queryObject.list();
-
- timer.stop();
- if ( AbstractDao.log.isDebugEnabled() )
- AbstractDao.log
- .debug( "Fetching probeResults from resultSet " + resultSet.getId() + " for gene " + gene.getId()
- + "and " + arrayDesignIds.size() + "arrays took : " + timer.getTime() + " ms" );
-
- return results;
- }
-
@Override
public List findInResultSet( ExpressionAnalysisResultSet resultSet,
Double threshold, int limit, int minNumberOfResults ) {
+ Assert.notNull( resultSet, "The result set must not be null." );
+ Assert.isTrue( minNumberOfResults > 0, "Minimum number of results must be greater than zero." );
- if ( minNumberOfResults < 1 ) {
- throw new IllegalArgumentException( "Minimum number of results must be greater than one" );
- }
-
- List results = new ArrayList<>();
-
- if ( resultSet == null ) {
- return results;
- }
-
- results = differentialExpressionResultCache.getTopHits( resultSet );
- if ( results != null && results.size() >= minNumberOfResults ) {
+ // check for top hits in cache
+ List cachedResults = differentialExpressionResultCache.getTopHits( resultSet );
+ if ( cachedResults != null && cachedResults.size() >= minNumberOfResults ) {
AbstractDao.log.info( "Top hits already in cache" );
- return results;
+ return cachedResults;
}
- results = new ArrayList<>();
-
- // get it.
-
+ // retrieve top hits from database
StopWatch timer = new StopWatch();
timer.start();
- String qs = DifferentialExpressionResultDaoImpl.fetchResultsBySingleResultSetQuery
- + " and r.correctedPvalue <= :threshold order by r.correctedPvalue";
+ String qs = "select r from DifferentialExpressionAnalysisResult r "
+ + "where r.resultSet = :resultSet and r.correctedPvalue <= :threshold "
+ + "order by r.correctedPvalue";
List> qResult = getSessionFactory().getCurrentSession().createQuery( qs )
.setParameter( "resultSet", resultSet )
@@ -548,140 +411,31 @@ public List findInResultSet( ExpressionAnalys
if ( qResult.size() < minNumberOfResults ) {
// FIXME this is kind of dumb. If we always return the top minimum, why not just always get that?
AbstractDao.log.info( "Too few results met threshold, repeating to just get the top hits" );
- qs = DifferentialExpressionResultDaoImpl.fetchResultsBySingleResultSetQuery + " order by r.correctedPvalue";
+ qs = "select r from DifferentialExpressionAnalysisResult r "
+ + "where r.resultSet = :resultSet "
+ + "order by r.correctedPvalue";
qResult = getSessionFactory().getCurrentSession().createQuery( qs )
.setParameter( "resultSet", resultSet )
.setMaxResults( minNumberOfResults )
.list();
}
+ List results = new ArrayList<>();
for ( Object o : qResult ) {
- DifferentialExpressionValueObject probeResult = new DifferentialExpressionValueObject(
- ( DifferentialExpressionAnalysisResult ) o );
+ DifferentialExpressionAnalysisResult dear = ( DifferentialExpressionAnalysisResult ) o;
+ Hibernate.initialize( dear.getProbe() );
+ DifferentialExpressionValueObject probeResult = new DifferentialExpressionValueObject( dear );
results.add( probeResult );
}
- timer.stop();
- if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
- }
-
differentialExpressionResultCache.addToTopHitsCache( resultSet, results );
- return results;
- }
-
- /**
- * Given a list of result sets finds the results that met the given threshold
- *
- * @param limit - max number of results to return.
- */
- @Override
- public Map> findInResultSets(
- Collection resultsAnalyzed, double threshold, int limit ) {
-
- Map> results = new HashMap<>();
-
- if ( resultsAnalyzed.size() == 0 ) {
- return results;
- }
-
- // Integer bin = Math.log10(threshold);
-
- StopWatch timer = new StopWatch();
- timer.start();
- String qs = DifferentialExpressionResultDaoImpl.fetchResultsByResultSetQuery
- + " and r.correctedPvalue < :threshold order by r.correctedPvalue";
-
- List> qResult = getSessionFactory().getCurrentSession().createQuery( qs )
- .setParameterList( "resultsAnalyzed", resultsAnalyzed )
- .setParameter( "threshold", threshold )
- .setMaxResults( limit )
- .list();
-
- for ( Object o : qResult ) {
-
- Object[] oa = ( Object[] ) o;
- ExpressionAnalysisResultSet ee = ( ExpressionAnalysisResultSet ) oa[0];
- DifferentialExpressionAnalysisResult probeResult = ( DifferentialExpressionAnalysisResult ) oa[1];
-
- if ( !results.containsKey( ee ) ) {
- results.put( ee, new ArrayList() );
- }
-
- results.get( ee ).add( probeResult );
- }
-
timer.stop();
if ( timer.getTime() > 1000 ) {
AbstractDao.log.info( "Diff ex results: " + timer.getTime() + " ms" );
}
- return results;
- }
-
- @Override
- public DifferentialExpressionAnalysis getAnalysis( ExpressionAnalysisResultSet rs ) {
- return ( DifferentialExpressionAnalysis ) this.getSessionFactory().getCurrentSession()
- .createQuery( "select distinct a from DifferentialExpressionAnalysis a join a.resultSets r where r=:r" )
- .setParameter( "r", rs )
- .uniqueResult();
- }
-
- @Override
- public Collection getExperimentalFactors(
- DifferentialExpressionAnalysisResult differentialExpressionAnalysisResult ) {
-
- //noinspection unchecked
- return this.getSessionFactory().getCurrentSession().createQuery( "select ef from ExpressionAnalysisResultSet rs"
- + " inner join rs.results r inner join rs.experimentalFactors ef where r=:differentialExpressionAnalysisResult" )
- .setParameter( "differentialExpressionAnalysisResult", differentialExpressionAnalysisResult ).list();
-
- }
-
- @Override
- public Map> getExperimentalFactors(
- Collection differentialExpressionAnalysisResults ) {
- StopWatch timer = new StopWatch();
- timer.start();
- Map> factorsByResult = new HashMap<>();
- if ( differentialExpressionAnalysisResults.isEmpty() ) {
- return factorsByResult;
- }
-
- //language=HQL
- final String queryString = "select rs.experimentalFactors, r from ExpressionAnalysisResultSet rs"
- + " inner join rs.results r where r in (:differentialExpressionAnalysisResults)";
-
- List> qr = this.getSessionFactory().getCurrentSession()
- .createQuery( queryString )
- .setParameterList( "differentialExpressionAnalysisResults", differentialExpressionAnalysisResults )
- .list();
-
- if ( qr == null || qr.isEmpty() )
- return factorsByResult;
-
- for ( Object o : qr ) {
- Object[] ar = ( Object[] ) o;
- ExperimentalFactor f = ( ExperimentalFactor ) ar[0];
- DifferentialExpressionAnalysisResult res = ( DifferentialExpressionAnalysisResult ) ar[1];
-
- assert differentialExpressionAnalysisResults.contains( res );
-
- if ( !factorsByResult.containsKey( res ) ) {
- factorsByResult.put( res, new HashSet() );
- }
-
- factorsByResult.get( res ).add( f );
-
- if ( AbstractDao.log.isDebugEnabled() )
- AbstractDao.log.debug( res );
- }
- timer.stop();
- if ( timer.getTime() > 1000 ) {
- AbstractDao.log.info( "factors by results: " + timer.getTime() + " ms" );
- }
- return factorsByResult;
+ return results;
}
/**
@@ -690,9 +444,6 @@ public Map>
@Override
public Map loadContrastDetailsForResults( Collection ids ) {
//language=SQL
- final String queryString = "SELECT DISTINCT c.ID, c.LOG_FOLD_CHANGE, c.FACTOR_VALUE_FK,"
- + " c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK, c.PVALUE FROM CONTRAST_RESULT c"
- + " WHERE c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK IN (:ids) ";
Map probeResults = new HashMap<>();
@@ -700,7 +451,10 @@ public Map loadContrastDetailsForResults( Collection
return probeResults;
}
- SQLQuery query = this.getSessionFactory().getCurrentSession().createSQLQuery( queryString );
+ SQLQuery query = this.getSessionFactory().getCurrentSession()
+ .createSQLQuery( "SELECT DISTINCT c.ID, c.LOG_FOLD_CHANGE, c.FACTOR_VALUE_FK,"
+ + " c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK, c.PVALUE FROM CONTRAST_RESULT c"
+ + " WHERE c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK IN (:ids) " );
int BATCH_SIZE = 2000; // previously: 500, then 1000. New optimized query is plenty fast.
StopWatch timer = new StopWatch();
@@ -737,36 +491,15 @@ public Map loadContrastDetailsForResults( Collection
if ( timer.getTime() > 2000 ) {
AbstractDao.log.info( "Fetch " + batch.size() + " results with contrasts: " + timer.getTime()
- + "ms; query was\n " + queryString.replace( ":ids", StringUtils.join( batch, "," ) ) );
+ + "ms; query was\n " + ( "SELECT DISTINCT c.ID, c.LOG_FOLD_CHANGE, c.FACTOR_VALUE_FK,"
+ + " c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK, c.PVALUE FROM CONTRAST_RESULT c"
+ + " WHERE c.DIFFERENTIAL_EXPRESSION_ANALYSIS_RESULT_FK IN (:ids) " ).replace( ":ids", StringUtils.join( batch, "," ) ) );
}
}
return probeResults;
}
- @Override
- public void thaw( final Collection results ) {
- for ( DifferentialExpressionAnalysisResult result : results ) {
- Hibernate.initialize( result );
- CompositeSequence cs = result.getProbe();
- Hibernate.initialize( cs );
- Hibernate.initialize( result.getContrasts() );
- }
- }
-
- @Override
- public void thaw( final DifferentialExpressionAnalysisResult result ) {
- Hibernate.initialize( result );
-
- CompositeSequence cs = result.getProbe();
- Hibernate.initialize( cs );
-
- Collection contrasts = result.getContrasts();
- for ( ContrastResult contrast : contrasts ) {
- Hibernate.initialize( contrast.getFactorValue() );
- }
- }
-
@Override
public Map> find( Gene gene,
double threshold, int limit ) {
@@ -775,14 +508,16 @@ public Map 0.0 ) {
sql = sql + " and d.CORRECTED_PVALUE < :threshold ";
}
if ( limit > 0 ) {
- sql = sql + " order by d.PVALUE ASC ";
+ sql = sql + " order by d.PVALUE";
}
SQLQuery query = session.createSQLQuery( sql );
@@ -849,9 +584,10 @@ public Map ees = session.createQuery(
- "select ee, rs from ExpressionAnalysisResultSet rs join fetch rs.experimentalFactors join rs.analysis a join a.experimentAnalyzed ee"
- + " where rs.id in (:rsids)" )
+ List