Changeset 1501 for trunk/src


Ignore:
Timestamp:
Feb 7, 2011, 4:07:54 PM (9 years ago)
Author:
robert@…
Message:
  • Number of seconds for the rest controller to keep data in cache is now a configuration option
  • After searching, it is possible to choose which action to perform on the search results.
Location:
trunk/src/groovy/dbnp/query
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/groovy/dbnp/query/SampleSearch.groovy

    r1482 r1501  
    6262         */
    6363        @Override
    64         void execute() {
    65                 super.execute();
    66 
     64        void executeAnd() {
    6765                // If no criteria are found, return all samples
    6866                if( !criteria || criteria.size() == 0 ) {
     
    8078                        def studies = Study.findAll().findAll { it.canRead( this.user ) };
    8179
    82                         studies = filterOnStudyCriteria( studies );
     80                        studies = filterStudiesOnStudyCriteria( studies );
    8381
    8482                        if( studies.size() == 0 ) {
     
    116114
    117115        /**
    118          * Filters the given list of samples on the sample criteria
    119          * @param samples       Original list of samples
    120          * @return                      List with all samples that match the Sample-criteria
    121          */
    122         protected List filterOnStudyCriteria( List studies ) {
     116        * Searches for samples based on the given criteria. Only one of the criteria have to be satisfied and
     117        * criteria for the different entities are satisfied as follows:
     118        *
     119        *               Sample.title = 'abc'
     120        *                               Samples are returned from studies with title 'abc'
     121        *
     122        *               Subject.species = 'human'
     123        *                               Samples are returned from subjects with species = 'human'
     124        *
     125        *               Sample.name = 'sample 1'
     126        *                               Samples are returned with name = 'sample 1'
     127        *
     128        *               Event.startTime = '0s'
     129        *                               Samples are returned from subjects that have had an event with start time = '0s'
     130        *
     131        *               SamplingEvent.startTime = '0s'
     132        *                               Samples are returned that have originated from a sampling event with start time = '0s'
     133        *
     134        *               Assay.module = 'metagenomics'
     135        *                               Samples are returned that have been processed in an assay with module = metagenomics
     136        *
     137        * When searching for more than one criterion per entity, these are taken separately. Searching for
     138        *
     139        *               Subject.species = 'human'
     140        *               Subject.name = 'Jan'
     141        *
     142        *  will result in all samples from a human subject or a subject named 'Jan'. Samples from a mouse subject
     143        *  named 'Jan' or a human subject named 'Kees' will also satisfy the criteria.
     144        *
     145        */
     146   @Override
     147   void executeOr() {
     148           // We expect the sample criteria to be the most discriminative, and discard
     149           // the most samples. (e.g. by searching on sample title of sample type). For
     150           // that reason we first look through the list of studies. However, when the
     151           // user didn't enter any sample criteria, this will be an extra step, but doesn't
     152           // cost much time to process.
     153           def samples = []
     154           def allSamples = Sample.list().findAll { it.parent?.canRead( this.user ) }.toList();
     155
     156           // If no criteria are found, return all samples
     157           if( !criteria || criteria.size() == 0 ) {
     158                   results = allSamples
     159                   return;
     160           }
     161           
     162           samples = ( samples + filterSamplesOnStudyCriteria( allSamples - samples ) ).unique();
     163           samples = ( samples + filterOnSubjectCriteria( allSamples - samples ) ).unique();
     164           samples = ( samples + filterOnSampleCriteria( allSamples - samples ) ).unique();
     165           samples = ( samples + filterOnEventCriteria( allSamples - samples ) ).unique();
     166           samples = ( samples + filterOnSamplingEventCriteria( allSamples - samples ) ).unique();
     167           samples = ( samples + filterOnAssayCriteria( allSamples - samples ) ).unique();
     168           
     169           samples = ( samples + filterOnModuleCriteria( allSamples - samples ) ).unique();
     170           
     171           // Save matches
     172           results = samples;
     173   }
     174       
     175        /**
     176         * Filters the given list of studies on the study criteria
     177         * @param studies       Original list of studies
     178         * @return                      List with all samples that match the Study-criteria
     179         */
     180        protected List filterStudiesOnStudyCriteria( List studies ) {
    123181                return filterOnTemplateEntityCriteria(studies, "Study", { study, criterion -> return criterion.getFieldValue( study ) })
    124182        }
     183       
     184        /**
     185        * Filters the given list of samples on the sample criteria
     186        * @param samples        Original list of samples
     187        * @return                       List with all samples that match the Study-criteria
     188        */
     189   protected List filterSamplesOnStudyCriteria( List samples ) {
     190           return filterOnTemplateEntityCriteria(samples, "Study", { study, criterion ->
     191                   return criterion.getFieldValue( study.parent )
     192           })
     193   }
     194
    125195
    126196        /**
     
    180250                        return [];
    181251
    182                 if( getEntityCriteria( 'Assay' ).size() == 0 )
    183                         return samples
    184 
    185252                // There is no sample.assays property, so we have to look for assays another way: just find
    186253                // all assays that match the criteria
    187254                def criteria = getEntityCriteria( 'Assay' );
     255               
     256                if( getEntityCriteria( 'Assay' ).size() == 0 ) {
     257                        if( searchMode == SearchMode.and )
     258                                return samples
     259                        else if( searchMode == SearchMode.or )
     260                                return [];
     261                }
     262
    188263                def assays = filterEntityList( Assay.list(), criteria, { assay, criterion ->
    189264                        if( !assay )
    190265                                return false
    191266
    192                         return criterion.matchOne( assay );
     267                        return criterion.matchEntity( assay );
    193268                });
    194269
     
    197272                        return [];
    198273
    199                 // Save sample data for later use
    200                 saveResultFields( samples, criteria, { sample, criterion ->
    201                         def sampleAssays = Assay.findByStudy( sample.parent ).findAll { it.samples?.contains( sample ) };
    202                         if( sampleAssays && sampleAssays.size() > 0 )
    203                                 return sampleAssays.collect( criterion.getFieldValue( it ) )
    204                         else
    205                                 return null
    206                 });
    207 
    208274                // Now filter the samples on whether they are attached to the filtered assays
    209                 return samples.findAll { sample ->
     275                def matchingSamples = samples.findAll { sample ->
    210276                        if( !sample.parent )
    211277                                return false;
     
    222288                        return false;
    223289                }
     290               
     291                // Save sample data for later use
     292                println samples
     293                println "Find values for " + matchingSamples + " and " + criteria
     294                saveResultFields( matchingSamples, criteria, { sample, criterion ->
     295                        println "Find value for " + sample + " and " + criterion
     296                        def sampleAssays = Assay.findByParent( sample.parent ).findAll { it.samples?.contains( sample ) };
     297                        if( sampleAssays && sampleAssays.size() > 0 )
     298                                return sampleAssays.collect { criterion.getFieldValue( it ) }
     299                        else
     300                                return null
     301                });
     302       
     303                return matchingSamples;
    224304        }
    225305
  • trunk/src/groovy/dbnp/query/Search.groovy

    r1487 r1501  
    3030import org.dbnp.gdt.*
    3131
     32/**
     33* Available boolean operators for searches
     34* @author robert
     35*
     36*/
     37enum SearchMode {
     38   and, or
     39}
     40
    3241class Search {
    33         public String entity;
    3442        public SecUser user;
    3543        public Date executionDate;
    3644        public int id;  // Is only used when this query is saved in session
    3745
     46        public String entity;
     47        public SearchMode searchMode = SearchMode.and
     48       
    3849        protected List criteria;
    3950        protected List results;
     
    4253        public List getCriteria() { return criteria; }
    4354        public void setCriteria( List c ) { criteria = c; }
     55        public void addCriterion( Criterion c ) {
     56                if( criteria )
     57                        criteria << c;
     58                else
     59                        criteria = [c];
     60        }
    4461
    4562        public List getResults() { return results; }
    4663        public void setResults( List r ) { results = r; }
     64        public List filterResults( List selectedIds ) {
     65                if( !selectedIds || !results )
     66                        return results
     67                       
     68                return results.findAll {
     69                        selectedIds.contains( it.id )
     70                }
     71        }
     72       
    4773       
    4874        public Map getResultFields() { return resultFields; }
     
    83109
    84110        /**
    85          * Executes a search based on the given criteria. Should be filled in by
    86          * subclasses searching for a specific entity
     111         * Executes a search based on the given criteria.
    87112         */
    88113        public void execute() {
    89114                this.executionDate = new Date();
    90         }
     115               
     116                switch( searchMode ) {
     117                        case SearchMode.and:
     118                                executeAnd();
     119                                break;
     120                        case SearchMode.or:
     121                                executeOr();
     122                                break;
     123                }
     124        }
     125       
     126        /**
     127         * Executes an inclusive (AND) search based on the given criteria. Should be filled in by
     128         * subclasses searching for a specific entity
     129         */
     130        public void executeAnd() {
     131               
     132        }
     133       
     134        /**
     135        * Executes an exclusive (OR) search based on the given criteria. Should be filled in by
     136        * subclasses searching for a specific entity
     137        */
     138   public void executeOr() {
     139           
     140   }
    91141
    92142        /**
     
    112162        protected List filterEntityList( List entities, List<Criterion> criteria, Closure check ) {
    113163                if( !entities || !criteria || criteria.size() == 0 ) {
    114                         return entities;
    115                 }
    116 
     164                        if( searchMode == SearchMode.and )
     165                                return entities;
     166                        else if( searchMode == SearchMode.or )
     167                                return []
     168                }
     169               
    117170                return entities.findAll { entity ->
    118                         for( criterion in criteria ) {
    119                                 if( !check( entity, criterion ) ) {
    120                                         return false;
    121                                 }
     171                        if( searchMode == SearchMode.and ) {
     172                                for( criterion in criteria ) {
     173                                        if( !check( entity, criterion ) ) {
     174                                                return false;
     175                                        }
     176                                }
     177                                return true;
     178                        } else if( searchMode == SearchMode.or ) {
     179                                for( criterion in criteria ) {
     180                                        if( check( entity, criterion ) ) {
     181                                                return true;
     182                                        }
     183                                }
     184                                return false;
    122185                        }
    123                         return true;
    124186                }
    125187        }
     
    133195         */
    134196        public static def prepare( def value, TemplateFieldType type ) {
     197                if( value == null )
     198                        return value
     199                       
    135200                switch (type) {
    136201                        case TemplateFieldType.DATE:
     
    185250                }
    186251
    187         }
    188        
     252        }       
    189253       
    190254        /**
     
    201265                        def value = valueCallback( study, criterion );
    202266                       
    203                         if( value == null )
     267                        if( value == null ) {
    204268                                return false
     269                        }
     270
    205271                        if( value instanceof Collection ) {
    206272                                return criterion.matchAny( value )
     
    230296                def ctx = ApplicationHolder.getApplication().getMainContext();
    231297                def moduleCommunicationService = ctx.getBean("moduleCommunicationService");
    232                        
     298               
     299                def allEntities = []
     300                if( searchMode == SearchMode.or ) {
     301                        allEntities += entities;
     302                        entities = [];
     303                }
     304               
    233305                // Loop through all modules and check whether criteria have been given
    234306                // for that module
     
    250322                                        def json = moduleCommunicationService.callModuleRestMethodJSON( module.url, callUrl );
    251323
    252                                         // The data has been retrieved. Now walk through all criteria to filter the samples
    253                                         entities = filterEntityList( entities, moduleCriteria, { entity, criterion ->
     324                                        Closure checkClosure = { entity, criterion ->
    254325                                                // Find the value of the field in this sample. That value is still in the
    255326                                                // JSON object
     
    268339                                                }
    269340                                               
    270                                                 // Loop through all values and match any
    271                                                 for( val in value ) {
    272                                                         // Convert numbers to a long or double in order to process them correctly
     341                                                // Convert numbers to a long or double in order to process them correctly
     342                                                def values = value.collect { val ->
    273343                                                        val = val.toString();
    274344                                                        if( val.isLong() ) {
     
    277347                                                                val = Double.parseDouble( val );
    278348                                                        }
    279                                                        
     349                                                        return val;
     350                                                }
     351
     352                                                // Loop through all values and match any
     353                                                for( val in values ) {
    280354                                                        if( criterion.match( val ) )
    281355                                                                return true;
     
    283357                                               
    284358                                                return false;
    285                                         });
     359                                        }
     360                                       
     361                                        // The data has been retrieved. Now walk through all criteria to filter the samples
     362                                        if( searchMode == SearchMode.and ) {
     363                                                entities = filterEntityList( entities, moduleCriteria, checkClosure );
     364                                        } else if( searchMode == SearchMode.or ) {
     365                                                entities += filterEntityList( allEntities - entities, moduleCriteria, checkClosure );
     366                                                entities = entities.unique();
     367                                        }
    286368                                                                               
    287369                                } catch( Exception e ) {
     
    321403                        resultFields[ id ] = [:]
    322404               
     405                // Handle special cases
     406                if( value == null )
     407                        value = "";
     408               
     409                if( value instanceof Collection ) {
     410                        value = value.findAll { it != null }
     411                }
     412               
    323413                resultFields[ id ][ fieldName ] = value;
    324414        }
  • trunk/src/groovy/dbnp/query/StudySearch.groovy

    r1487 r1501  
    2424class StudySearch extends Search {
    2525        private static final log = LogFactory.getLog(this);
    26        
     26
    2727        public StudySearch() {
    2828                super();
     
    6363         */
    6464        @Override
    65         void execute() {
    66                 super.execute();
    67 
     65        void executeAnd() {
    6866                def studies = Study.list().findAll { it.canRead( this.user ) };
    6967
     
    8179                studies = filterOnSamplingEventCriteria( studies );
    8280                studies = filterOnAssayCriteria( studies );
     81
     82                studies = filterOnModuleCriteria( studies );
     83
     84                // Save matches
     85                results = studies;
     86        }
     87
     88        /**
     89         * Searches for studies based on the given criteria. Only one criteria have to be satisfied and
     90         * criteria for the different entities are satisfied as follows:
     91         *
     92         *              Study.title = 'abc'
     93         *                              The returned study will have title 'abc'
     94         *
     95         *              Subject.species = 'human'
     96         *                              The returned study will have one or more subjects with species = 'human'
     97         *
     98         *              Sample.name = 'sample 1'
     99         *                              The returned study will have one or more samples with name = 'sample 1'
     100         *
     101         *              Event.startTime = '0s'
     102         *                              The returned study will have one or more events with start time = '0s'
     103         *
     104         *              Assay.module = 'metagenomics'
     105         *                              The returned study will have one or more assays with module = 'metagenomics'
     106         *
     107         * When searching the system doesn't look at the connections between different entities. This means,
     108         * the system doesn't look for human subjects having a sample with name 'sample 1'. The sample 1 might
     109         * as well belong to a mouse subject and still the study satisfies the criteria.
     110         *
     111         * When searching for more than one criterion per entity, these are taken separately. Searching for
     112         *
     113         *              Subject.species = 'human'
     114         *              Subject.name = 'Jan'
     115         *
     116         *  will result in all studies having a human subject or a subject named 'Jan'. Studies with only a
     117         *  mouse subject named 'Jan' or a human subject named 'Kees' will satisfy the criteria.
     118         *
     119         */
     120        @Override
     121        void executeOr() {
     122                def allStudies = Study.list().findAll { it.canRead( this.user ) };
     123
     124                // If no criteria are found, return all studies
     125                if( !criteria || criteria.size() == 0 ) {
     126                        results = allStudies;
     127                        return;
     128                }
     129
     130                // Perform filters
     131                def studies = []
     132                studies = ( studies + filterOnStudyCriteria( allStudies - studies ) ).unique();
     133                studies = ( studies + filterOnSubjectCriteria( allStudies - studies ) ).unique();
     134                studies = ( studies + filterOnSampleCriteria( allStudies - studies ) ).unique();
     135                studies = ( studies + filterOnEventCriteria( allStudies - studies ) ).unique();
     136                studies = ( studies + filterOnSamplingEventCriteria( allStudies - studies ) ).unique();
     137                studies = ( studies + filterOnAssayCriteria( allStudies - studies ) ).unique();
    83138               
    84                 studies = filterOnModuleCriteria( studies );
     139                studies = ( studies + filterOnModuleCriteria( allStudies - studies ) ).unique();
    85140               
    86141                // Save matches
Note: See TracChangeset for help on using the changeset viewer.