ubic.gemma.persistence.service.analysis.expression.diff.DifferentialExpressionAnalysisDaoImpl.java Source code

Java tutorial

Introduction

Here is the source code for ubic.gemma.persistence.service.analysis.expression.diff.DifferentialExpressionAnalysisDaoImpl.java

Source

/*
 * The Gemma project.
 *
 * Copyright (c) 2006-2007 University of British Columbia
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package ubic.gemma.persistence.service.analysis.expression.diff;

import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.hibernate.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import ubic.gemma.model.analysis.Investigation;
import ubic.gemma.model.analysis.expression.diff.*;
import ubic.gemma.model.expression.designElement.CompositeSequence;
import ubic.gemma.model.expression.experiment.*;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.Taxon;
import ubic.gemma.persistence.service.AbstractDao;
import ubic.gemma.persistence.service.analysis.AnalysisDaoBase;
import ubic.gemma.persistence.util.CommonQueries;
import ubic.gemma.persistence.util.EntityUtils;

import java.math.BigInteger;
import java.util.*;

/**
 * @author paul
 * @see    DifferentialExpressionAnalysis
 */
@Repository
class DifferentialExpressionAnalysisDaoImpl extends AnalysisDaoBase<DifferentialExpressionAnalysis>
        implements DifferentialExpressionAnalysisDao {

    @Autowired
    public DifferentialExpressionAnalysisDaoImpl(SessionFactory sessionFactory) {
        super(DifferentialExpressionAnalysis.class, sessionFactory);
    }

    @Override
    public Integer countDownregulated(ExpressionAnalysisResultSet par, double threshold) {
        String query = "select count(distinct r) from ExpressionAnalysisResultSet rs inner join rs.results r "
                + "join r.contrasts c where rs = :rs and r.correctedPvalue < :threshold and c.tstat < 0";

        String[] paramNames = { "rs", "threshold" };
        Object[] objectValues = { par, threshold };

        List<?> qresult = this.getHibernateTemplate().findByNamedParam(query, paramNames, objectValues);

        if (qresult.isEmpty()) {
            AbstractDao.log.warn("No count returned");
            return 0;
        }
        Long count = (Long) qresult.iterator().next();

        AbstractDao.log.debug("Found " + count + " downregulated genes in result set (" + par.getId()
                + ") at a corrected pvalue threshold of " + threshold);

        return count.intValue();
    }

    @Override
    public Integer countProbesMeetingThreshold(ExpressionAnalysisResultSet ears, double threshold) {

        String query = "select count(distinct r) from ExpressionAnalysisResultSet rs inner join rs.results r where rs = :rs and r.correctedPvalue < :threshold";

        String[] paramNames = { "rs", "threshold" };
        Object[] objectValues = { ears, threshold };

        List<?> qresult = this.getHibernateTemplate().findByNamedParam(query, paramNames, objectValues);

        if (qresult.isEmpty()) {
            AbstractDao.log.warn("No count returned");
            return 0;
        }
        Long count = (Long) qresult.iterator().next();

        AbstractDao.log.debug("Found " + count + " differentially expressed genes in result set (" + ears.getId()
                + ") at a corrected pvalue threshold of " + threshold);

        return count.intValue();
    }

    @Override
    public Integer countUpregulated(ExpressionAnalysisResultSet par, double threshold) {
        String query = "select count(distinct r) from ExpressionAnalysisResultSet rs inner join rs.results r"
                + " join r.contrasts c where rs = :rs and r.correctedPvalue < :threshold and c.tstat > 0";

        String[] paramNames = { "rs", "threshold" };
        Object[] objectValues = { par, threshold };

        List<?> qresult = this.getHibernateTemplate().findByNamedParam(query, paramNames, objectValues);

        if (qresult.isEmpty()) {
            AbstractDao.log.warn("No count returned");
            return 0;
        }
        Long count = (Long) qresult.iterator().next();

        AbstractDao.log.debug("Found " + count + " upregulated genes in result set (" + par.getId()
                + ") at a corrected pvalue threshold of " + threshold);

        return count.intValue();
    }

    @Override
    public Collection<DifferentialExpressionAnalysis> find(Gene gene, ExpressionAnalysisResultSet resultSet,
            double threshold) {
        final String findByResultSet = "select distinct r from DifferentialExpressionAnalysis a"
                + "   inner join a.experimentAnalyzed e inner join e.bioAssays ba inner join ba.arrayDesignUsed ad"
                + " inner join ad.compositeSequences cs inner join cs.biologicalCharacteristic bs inner join "
                + "bs.bioSequence2GeneProduct bs2gp inner join bs2gp.geneProduct gp inner join gp.gene g"
                + " inner join a.resultSets rs inner join rs.results r where r.probe=cs and g=:gene and rs=:resultSet"
                + " and r.correctedPvalue < :threshold";

        String[] paramNames = { "gene", "resultSet", "threshold" };
        Object[] objectValues = { gene, resultSet, threshold };

        //noinspection unchecked
        return this.getHibernateTemplate().findByNamedParam(findByResultSet, paramNames, objectValues);
    }

    @Override
    public Collection<DifferentialExpressionAnalysis> findByFactor(ExperimentalFactor ef) {

        // subset factorValues factors.
        @SuppressWarnings("unchecked")
        Collection<DifferentialExpressionAnalysis> result = this.getHibernateTemplate().findByNamedParam(
                "select distinct a from DifferentialExpressionAnalysis a join a.subsetFactorValue ssf"
                        + " join ssf.experimentalFactor efa where efa = :ef ",
                "ef", ef);

        // factors used in the analysis.
        //noinspection unchecked
        result.addAll(this.getHibernateTemplate().findByNamedParam(
                "select distinct a from DifferentialExpressionAnalysis a join a.resultSets rs"
                        + " left join rs.baselineGroup bg join rs.experimentalFactors efa where efa = :ef ",
                "ef", ef));

        return result;
    }

    @Override
    public Map<Long, Collection<DifferentialExpressionAnalysis>> findByInvestigationIds(
            Collection<Long> investigationIds) {

        Map<Long, Collection<DifferentialExpressionAnalysis>> results = new HashMap<>();
        //language=HQL
        final String queryString = "select distinct e, a from DifferentialExpressionAnalysis a"
                + "   inner join a.experimentAnalyzed e where e.id in (:eeIds)";
        List<?> qresult = this.getHibernateTemplate().findByNamedParam(queryString, "eeIds", investigationIds);
        for (Object o : qresult) {
            Object[] oa = (Object[]) o;
            BioAssaySet bas = (BioAssaySet) oa[0];
            DifferentialExpressionAnalysis dea = (DifferentialExpressionAnalysis) oa[1];
            Long id = bas.getId();
            if (!results.containsKey(id)) {
                results.put(id, new HashSet<DifferentialExpressionAnalysis>());
            }
            results.get(id).add(dea);
        }
        return results;
    }

    @Override
    public Collection<BioAssaySet> findExperimentsWithAnalyses(Gene gene) {

        StopWatch timer = new StopWatch();
        timer.start();

        Collection<CompositeSequence> probes = CommonQueries.getCompositeSequences(gene,
                this.getSessionFactory().getCurrentSession());
        Collection<BioAssaySet> result = new HashSet<>();
        if (probes.size() == 0) {
            return result;
        }

        if (timer.getTime() > 1000) {
            AbstractDao.log.info("Find probes: " + timer.getTime() + " ms");
        }
        timer.reset();
        timer.start();

        /*
         * Note: this query misses ExpressionExperimentSubSets. The native query was implemented because HQL was always
         * constructing a constraint on SubSets. See bug 2173.
         */
        final String queryToUse = "select e.ID from ANALYSIS a inner join INVESTIGATION e ON a.EXPERIMENT_ANALYZED_FK = e.ID "
                + "inner join BIO_ASSAY ba ON ba.EXPRESSION_EXPERIMENT_FK=e.ID "
                + " inner join BIO_MATERIAL bm ON bm.ID=ba.SAMPLE_USED_FK inner join TAXON t ON bm.SOURCE_TAXON_FK=t.ID "
                + " inner join COMPOSITE_SEQUENCE cs ON ba.ARRAY_DESIGN_USED_FK =cs.ARRAY_DESIGN_FK where cs.ID in "
                + " (:probes) and t.ID = :taxon";

        Taxon taxon = gene.getTaxon();

        int batchSize = 1000;
        Collection<CompositeSequence> batch = new HashSet<>();
        for (CompositeSequence probe : probes) {
            batch.add(probe);

            if (batch.size() == batchSize) {
                this.fetchExperimentsTestingGeneNativeQuery(batch, result, queryToUse, taxon);
                batch.clear();
            }
        }

        if (!batch.isEmpty()) {
            this.fetchExperimentsTestingGeneNativeQuery(batch, result, queryToUse, taxon);
        }

        if (timer.getTime() > 1000) {
            AbstractDao.log.info("Find experiments: " + timer.getTime() + " ms");
        }

        return result;
    }

    @Override
    public Map<ExpressionExperiment, Collection<DifferentialExpressionAnalysis>> getAnalyses(
            Collection<? extends BioAssaySet> experiments) {
        Map<ExpressionExperiment, Collection<DifferentialExpressionAnalysis>> result = new HashMap<>();

        StopWatch timer = new StopWatch();
        timer.start();
        final String query = "select distinct a from DifferentialExpressionAnalysis a inner join fetch a.resultSets res "
                + " inner join fetch res.baselineGroup"
                + " inner join fetch res.experimentalFactors facs inner join fetch facs.factorValues "
                + " inner join fetch res.hitListSizes where a.experimentAnalyzed.id in (:ees) ";

        //noinspection unchecked
        List<DifferentialExpressionAnalysis> r1 = this.getHibernateTemplate().findByNamedParam(query, "ees",
                EntityUtils.getIds(experiments));
        int count = 0;
        for (DifferentialExpressionAnalysis a : r1) {
            //noinspection SuspiciousMethodCalls // Ignoring subsets
            if (!result.containsKey(a.getExperimentAnalyzed())) {
                result.put((ExpressionExperiment) a.getExperimentAnalyzed(),
                        new HashSet<DifferentialExpressionAnalysis>());
            }
            //noinspection SuspiciousMethodCalls // Ignoring subsets
            result.get(a.getExperimentAnalyzed()).add(a);
            count++;
        }
        if (timer.getTime() > 1000) {
            AbstractDao.log.info("Fetch " + count + " analyses for " + result.size() + " experiments: "
                    + timer.getTime() + "ms; Query was:\n" + query);
        }
        timer.reset();
        timer.start();

        /*
         * Deal with the analyses of subsets of the experiments given being analyzed; but we keep things organized by
         * the source experiment. Maybe that is confusing.
         */
        String q2 = "select distinct a from ExpressionExperimentSubSet eess, DifferentialExpressionAnalysis a "
                + " inner join fetch a.resultSets res inner join fetch res.baselineGroup "
                + " inner join fetch res.experimentalFactors facs inner join fetch facs.factorValues"
                + " inner join fetch res.hitListSizes  "
                + " join eess.sourceExperiment see join a.experimentAnalyzed ee  where eess=ee and see.id in (:ees) ";
        //noinspection unchecked
        List<DifferentialExpressionAnalysis> r2 = this.getHibernateTemplate().findByNamedParam(q2, "ees",
                EntityUtils.getIds(experiments));

        if (!r2.isEmpty()) {
            count = 0;
            for (DifferentialExpressionAnalysis a : r2) {
                BioAssaySet experimentAnalyzed = a.getExperimentAnalyzed();

                assert experimentAnalyzed instanceof ExpressionExperimentSubSet;

                ExpressionExperiment sourceExperiment = ((ExpressionExperimentSubSet) experimentAnalyzed)
                        .getSourceExperiment();

                if (!result.containsKey(sourceExperiment)) {
                    result.put(sourceExperiment, new HashSet<DifferentialExpressionAnalysis>());
                }

                result.get(sourceExperiment).add(a);
                count++;
            }
            if (timer.getTime() > 1000) {
                AbstractDao.log.info("Fetch " + count + " subset analyses for " + result.size()
                        + " experiment subsets: " + timer.getTime() + "ms");
                AbstractDao.log.debug("Query for subsets was: " + q2);
            }
        }

        return result;

    }

    @Override
    public Collection<Long> getExperimentsWithAnalysis(Collection<Long> idsToFilter) {
        //language=HQL
        final String queryString = "select distinct e.id from DifferentialExpressionAnalysis a"
                + " inner join a.experimentAnalyzed e where e.id in (:eeIds)";
        //noinspection unchecked
        return this.getHibernateTemplate().findByNamedParam(queryString, "eeIds", idsToFilter);
    }

    @Override
    public Collection<Long> getExperimentsWithAnalysis(Taxon taxon) {
        //language=HQL
        final String queryString = "select distinct ee.id from DifferentialExpressionAnalysis"
                + " as doa inner join doa.experimentAnalyzed as ee " + "inner join ee.bioAssays as ba "
                + "inner join ba.sampleUsed as sample where sample.sourceTaxon = :taxon ";
        //noinspection unchecked
        return this.getHibernateTemplate().findByNamedParam(queryString, "taxon", taxon);
    }

    @Override
    public void thaw(final Collection<DifferentialExpressionAnalysis> expressionAnalyses) {
        for (DifferentialExpressionAnalysis ea : expressionAnalyses) {
            this.thaw(ea);
        }
    }

    @Override
    public void thaw(DifferentialExpressionAnalysis differentialExpressionAnalysis) {
        StopWatch timer = new StopWatch();
        timer.start();

        Session session = this.getSessionFactory().getCurrentSession();
        session.clear();

        session.buildLockRequest(LockOptions.NONE).lock(differentialExpressionAnalysis);
        Hibernate.initialize(differentialExpressionAnalysis);
        Hibernate.initialize(differentialExpressionAnalysis.getExperimentAnalyzed());
        session.buildLockRequest(LockOptions.NONE).lock(differentialExpressionAnalysis.getExperimentAnalyzed());
        Hibernate.initialize(differentialExpressionAnalysis.getExperimentAnalyzed().getBioAssays());

        Hibernate.initialize(differentialExpressionAnalysis.getProtocol());

        if (differentialExpressionAnalysis.getSubsetFactorValue() != null) {
            Hibernate.initialize(differentialExpressionAnalysis.getSubsetFactorValue());
        }

        Collection<ExpressionAnalysisResultSet> ears = differentialExpressionAnalysis.getResultSets();
        Hibernate.initialize(ears);
        for (ExpressionAnalysisResultSet ear : ears) {
            session.buildLockRequest(LockOptions.NONE).lock(ear);
            Hibernate.initialize(ear);
            Hibernate.initialize(ear.getExperimentalFactors());
        }
        if (timer.getTime() > 1000) {
            AbstractDao.log.info("Thaw: " + timer.getTime() + "ms");
        }
    }

    @Override
    public void thawResultSets(DifferentialExpressionAnalysis dea) {
        Hibernate.initialize(dea.getResultSets());
    }

    @Override
    public Map<Long, Collection<DifferentialExpressionAnalysisValueObject>> getAnalysesByExperimentIds(
            Collection<Long> expressionExperimentIds, int offset, int limit) {

        /*
         * There are three cases to consider: the ids are experiments; the ids are experiment subsets; the ids are
         * experiments that have subsets.
         */
        Map<Long, Collection<DifferentialExpressionAnalysisValueObject>> r = new HashMap<>();

        Map<Long, Collection<Long>> arrayDesignsUsed = CommonQueries
                .getArrayDesignsUsedEEMap(expressionExperimentIds, this.getSessionFactory().getCurrentSession());

        /*
         * Fetch analyses of experiments or subsets.
         */
        //noinspection unchecked
        Collection<DifferentialExpressionAnalysis> hits = this.getSessionFactory().getCurrentSession().createQuery(
                "select distinct a from DifferentialExpressionAnalysis a join fetch a.experimentAnalyzed e join"
                        + " fetch a.resultSets rs join fetch rs.hitListSizes where e.id in (:eeids)")
                .setParameterList("eeids", expressionExperimentIds).setFirstResult(offset)
                .setMaxResults(limit > 0 ? limit : -1).list();

        /*
         * FIXME the above query yields a warning
         * "firstResult/maxResults specified with collection fetch; applying in memory!"
         */

        Map<Long, Collection<FactorValue>> ee2fv = new HashMap<>();
        List<Object[]> fvs;

        if (!hits.isEmpty()) {
            // factor values for the experiments.
            //noinspection unchecked
            fvs = this.getSessionFactory().getCurrentSession().createQuery("select distinct ee.id, fv from "
                    + "ExpressionExperiment"
                    + " ee join ee.bioAssays ba join ba.sampleUsed bm join bm.factorValues fv where ee.id in (:ees)")
                    .setParameterList("ees", expressionExperimentIds).list();
            this.addFactorValues(ee2fv, fvs);

            // also get factor values for subsets - those not found yet.
            Collection<Long> used = new HashSet<>();
            for (DifferentialExpressionAnalysis a : hits) {
                used.add(a.getExperimentAnalyzed().getId());
            }

            List probableSubSetIds = ListUtils.removeAll(used, ee2fv.keySet());
            if (!probableSubSetIds.isEmpty()) {
                //noinspection unchecked
                fvs = this.getSessionFactory().getCurrentSession().createQuery("select distinct ee.id, fv from "
                        + "ExpressionExperimentSubSet"
                        + " ee join ee.bioAssays ba join ba.sampleUsed bm join bm.factorValues fv where ee.id in (:ees)")
                        .setParameterList("ees", probableSubSetIds).list();
                this.addFactorValues(ee2fv, fvs);
            }

        }

        /*
         * Subsets of those same experiments (there might not be any)
         */
        //noinspection unchecked
        List<DifferentialExpressionAnalysis> analysesOfSubsets = this.getSessionFactory().getCurrentSession()
                .createQuery("select distinct a from " + "ExpressionExperimentSubSet"
                        + " ee, DifferentialExpressionAnalysis a" + " join ee.sourceExperiment see "
                        + " join fetch a.experimentAnalyzed eeanalyzed where see.id in (:eeids) and ee=eeanalyzed")
                .setParameterList("eeids", expressionExperimentIds).list();

        if (!analysesOfSubsets.isEmpty()) {
            hits.addAll(analysesOfSubsets);

            Collection<Long> experimentSubsetIds = new HashSet<>();
            for (DifferentialExpressionAnalysis a : analysesOfSubsets) {
                ExpressionExperimentSubSet subset = (ExpressionExperimentSubSet) a.getExperimentAnalyzed();
                experimentSubsetIds.add(subset.getId());
            }

            // factor value information for the subset. The key output is the ID of the subset, not of the source
            // experiment.
            //noinspection unchecked
            fvs = this.getSessionFactory().getCurrentSession().createQuery("select distinct ee.id, fv from "
                    + "ExpressionExperimentSubSet"
                    + " ee join ee.bioAssays ba join ba.sampleUsed bm join bm.factorValues fv where ee.id in (:ees)")
                    .setParameterList("ees", experimentSubsetIds).list();
            this.addFactorValues(ee2fv, fvs);
        }

        // postprocesss...
        if (hits.isEmpty()) {
            return r;
        }
        Collection<DifferentialExpressionAnalysisValueObject> summaries = this.convertToValueObjects(hits,
                arrayDesignsUsed, ee2fv);

        for (DifferentialExpressionAnalysisValueObject an : summaries) {

            Long bioAssaySetId;
            if (an.getSourceExperiment() != null) {
                bioAssaySetId = an.getSourceExperiment();
            } else {
                bioAssaySetId = an.getBioAssaySetId();
            }
            if (!r.containsKey(bioAssaySetId)) {
                r.put(bioAssaySetId, new ArrayList<DifferentialExpressionAnalysisValueObject>());
            }
            r.get(bioAssaySetId).add(an);
        }

        return r;

    }

    @Override
    public void remove(DifferentialExpressionAnalysis analysis) {
        if (analysis == null) {
            throw new IllegalArgumentException("analysis cannot be null");
        }

        Session session = this.getSessionFactory().getCurrentSession();

        session.delete(session.load(DifferentialExpressionAnalysis.class, analysis.getId()));

        session.flush();
        session.clear();
    }

    @Override
    public Collection<DifferentialExpressionAnalysis> findByInvestigation(Investigation investigation) {
        Long id = investigation.getId();
        Collection<DifferentialExpressionAnalysis> results = new HashSet<>();

        //noinspection unchecked
        results.addAll(this.getSessionFactory().getCurrentSession().createQuery(
                "select distinct a from DifferentialExpressionAnalysis a where a.experimentAnalyzed.id=:eeid")
                .setParameter("eeid", id).list());

        /*
         * Deal with the analyses of subsets of the investigation. User has to know this is possible.
         */
        //noinspection unchecked
        results.addAll(this.getSessionFactory().getCurrentSession()
                .createQuery(
                        "select distinct a from ExpressionExperimentSubSet eess, DifferentialExpressionAnalysis a "
                                + "join eess.sourceExperiment see "
                                + "join a.experimentAnalyzed eeanalyzed where see.id=:eeid and eess=eeanalyzed")
                .setParameter("eeid", id).list());

        return results;
    }

    @Override
    @Deprecated // Not useful for DEAs, works for other analysis types.
    public void removeForExperiment(ExpressionExperiment ee) {
        throw new IllegalStateException(
                "!!! Not removing any analyses for experiment " + ee + ", use the service layer instead!");
    }

    private void addFactorValues(Map<Long, Collection<FactorValue>> ee2fv, List<Object[]> fvs) {
        for (Object[] oa : fvs) {
            Long eeId = (Long) oa[0];
            if (!ee2fv.containsKey(eeId)) {
                ee2fv.put(eeId, new HashSet<FactorValue>());
            }
            ee2fv.get(eeId).add((FactorValue) oa[1]);
        }
    }

    private Collection<DifferentialExpressionAnalysisValueObject> convertToValueObjects(
            Collection<DifferentialExpressionAnalysis> analyses, Map<Long, Collection<Long>> arrayDesignsUsed,
            Map<Long, Collection<FactorValue>> ee2fv) {
        Collection<DifferentialExpressionAnalysisValueObject> summaries = new HashSet<>();

        for (DifferentialExpressionAnalysis analysis : analyses) {

            Collection<ExpressionAnalysisResultSet> results = analysis.getResultSets();

            DifferentialExpressionAnalysisValueObject avo = new DifferentialExpressionAnalysisValueObject(analysis);

            BioAssaySet bioAssaySet = analysis.getExperimentAnalyzed();

            avo.setBioAssaySetId(bioAssaySet.getId()); // might be a subset.

            if (analysis.getSubsetFactorValue() != null) {
                avo.setSubsetFactorValue(new FactorValueValueObject(analysis.getSubsetFactorValue()));
                avo.setSubsetFactor(
                        new ExperimentalFactorValueObject(analysis.getSubsetFactorValue().getExperimentalFactor()));
                assert bioAssaySet instanceof ExpressionExperimentSubSet;
                avo.setSourceExperiment(((ExpressionExperimentSubSet) bioAssaySet).getSourceExperiment().getId());
                if (arrayDesignsUsed.containsKey(bioAssaySet.getId())) {
                    avo.setArrayDesignsUsed(arrayDesignsUsed.get(bioAssaySet.getId()));
                } else {
                    assert arrayDesignsUsed.containsKey(avo.getSourceExperiment());
                    avo.setArrayDesignsUsed(arrayDesignsUsed.get(avo.getSourceExperiment()));
                }
            } else {
                Collection<Long> adids = arrayDesignsUsed.get(bioAssaySet.getId());
                avo.setArrayDesignsUsed(adids);
            }

            for (ExpressionAnalysisResultSet resultSet : results) {

                DiffExResultSetSummaryValueObject desvo = new DiffExResultSetSummaryValueObject();
                desvo.setThreshold(DifferentialExpressionAnalysisValueObject.DEFAULT_THRESHOLD);
                for (ExperimentalFactor ef : resultSet.getExperimentalFactors()) {
                    desvo.getExperimentalFactors().add(new ExperimentalFactorValueObject(ef));
                }
                desvo.setArrayDesignsUsed(avo.getArrayDesignsUsed());
                desvo.setBioAssaySetAnalyzedId(bioAssaySet.getId()); // might be a subset.
                desvo.setResultSetId(resultSet.getId());
                desvo.setAnalysisId(analysis.getId());
                desvo.setFactorIds(EntityUtils.getIds(resultSet.getExperimentalFactors()));
                desvo.setNumberOfGenesAnalyzed(resultSet.getNumberOfGenesTested());
                desvo.setNumberOfProbesAnalyzed(resultSet.getNumberOfProbesTested());

                for (HitListSize hitList : resultSet.getHitListSizes()) {
                    if (hitList.getThresholdQvalue()
                            .equals(DifferentialExpressionAnalysisValueObject.DEFAULT_THRESHOLD)) {
                        if (hitList.getDirection().equals(Direction.UP)) {
                            desvo.setUpregulatedCount(hitList.getNumberOfProbes());
                        } else if (hitList.getDirection().equals(Direction.DOWN)) {
                            desvo.setDownregulatedCount(hitList.getNumberOfProbes());
                        } else if (hitList.getDirection().equals(Direction.EITHER)) {
                            desvo.setNumberOfDiffExpressedProbes(hitList.getNumberOfProbes());
                        }

                    }
                }

                if (resultSet.getBaselineGroup() != null) {
                    desvo.setBaselineGroup(new FactorValueValueObject(resultSet.getBaselineGroup()));
                }

                avo.getResultSets().add(desvo);

                assert ee2fv.containsKey(bioAssaySet.getId());
                this.populateWhichFactorValuesUsed(avo, ee2fv.get(bioAssaySet.getId()));

            }

            summaries.add(avo);
        }
        return summaries;
    }

    private void fetchExperimentsTestingGeneNativeQuery(Collection<CompositeSequence> probes,
            Collection<BioAssaySet> result, final String nativeQuery, Taxon taxon) {

        if (probes.isEmpty())
            return;

        SQLQuery nativeQ = this.getSessionFactory().getCurrentSession().createSQLQuery(nativeQuery);
        nativeQ.setParameterList("probes", EntityUtils.getIds(probes));
        nativeQ.setParameter("taxon", taxon);
        List<?> list = nativeQ.list();
        Set<Long> ids = new HashSet<>();
        for (Object o : list) {
            ids.add(((BigInteger) o).longValue());
        }
        if (!ids.isEmpty()) {
            //noinspection unchecked
            result.addAll(this.getHibernateTemplate()
                    .findByNamedParam("from ExpressionExperiment e where e.id in (:ids)", "ids", ids));
        }
    }

    /**
     * Figure out which factorValues were used for each of the experimental factors (excluding the subset factor)
     */
    private void populateWhichFactorValuesUsed(DifferentialExpressionAnalysisValueObject avo,
            Collection<FactorValue> fvs) {
        if (fvs == null || fvs.isEmpty()) {
            return;
        }
        ExperimentalFactorValueObject subsetFactor = avo.getSubsetFactor();

        for (FactorValue fv : fvs) {

            Long experimentalFactorId = fv.getExperimentalFactor().getId();

            if (subsetFactor != null && experimentalFactorId.equals(subsetFactor.getId())) {
                continue;
            }

            if (!avo.getFactorValuesUsed().containsKey(experimentalFactorId)) {
                avo.getFactorValuesUsed().put(experimentalFactorId, new HashSet<FactorValueValueObject>());
            }

            avo.getFactorValuesUsed().get(experimentalFactorId).add(new FactorValueValueObject(fv));

        }
    }
}