001    /**
002     * Houses9.java
003     * jCOLIBRI2 framework. 
004     * @author Juan A. Recio-García.
005     * GAIA - Group for Artificial Intelligence Applications
006     * http://gaia.fdi.ucm.es
007     * 23/10/2007
008     */
009    package jcolibri.test.recommenders.rec9;
010    
011    import java.util.ArrayList;
012    import java.util.Collection;
013    import java.util.HashMap;
014    import java.util.Map;
015    
016    import jcolibri.casebase.LinealCaseBase;
017    import jcolibri.cbraplications.StandardCBRApplication;
018    import jcolibri.cbrcore.Attribute;
019    import jcolibri.cbrcore.CBRCase;
020    import jcolibri.cbrcore.CBRCaseBase;
021    import jcolibri.cbrcore.CBRQuery;
022    import jcolibri.cbrcore.Connector;
023    import jcolibri.connector.PlainTextConnector;
024    import jcolibri.exception.ExecutionException;
025    import jcolibri.extensions.recommendation.casesDisplay.UserChoice;
026    import jcolibri.extensions.recommendation.conditionals.BuyOrQuit;
027    import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish;
028    import jcolibri.extensions.recommendation.navigationByProposing.CriticalUserChoice;
029    import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption;
030    import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod;
031    import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis;
032    import jcolibri.method.retrieve.RetrievalResult;
033    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod;
034    import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig;
035    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual;
036    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess;
037    import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore;
038    import jcolibri.method.retrieve.NNretrieval.NNConfig;
039    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
040    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
041    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
042    import jcolibri.method.retrieve.NNretrieval.similarity.local.Table;
043    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter;
044    import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter;
045    import jcolibri.method.retrieve.selection.SelectCases;
046    import jcolibri.test.recommenders.housesData.HouseDescription;
047    
048    /**
049     * Conversational (type A) flats recommender using Navigation by Proposing for both One-Off and Interated preference elicitation, and Filtered+NearestNeighbour+selectTopK retrieval.
050     * <br>
051     * This conversational recommender implements the Navigation by Proposing strategy. Instead of obtaining 
052     * the initial query asking to the user, it displays every item in the case base. This way, the user selects
053     * one similar to his/her requirements and the system refines the retrieval set for the following iteration. 
054     * Like other NbP recommenders it uses critiques to filter the working set of items and computes the Nearest Neighbour
055     * scoring to obtain the displayed items.
056     * <br>Summary:
057     * <ul>
058     * <li>Type: Conversational A
059     * <li>Case base: houses
060     * <li>One off Preference Elicitation: Choosing from table + critiques
061     * <li>Retrieval: Filtering + Nearest Neighbour + SelectTopK
062     * <li>Display: In table with critiques
063     * <li>Iterated Preference Elecitiation: Navigation by Proposing: More Like This
064     * </ul>
065     * 
066     * This recommender implements the following template:<br>
067     * <center><img src="../Template10_Cycle.jpg"/></center>
068     * 
069     * <br>Read the documentation of the recommenders extension for details about templates
070     * and recommender strategies: {@link jcolibri.extensions.recommendation}
071     * 
072     * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod
073     * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod
074     * @see jcolibri.method.retrieve.selection.SelectCases
075     * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod
076     * @see jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis
077     * 
078     * 
079     * @see jcolibri.test.recommenders.rec6.Houses6
080     * 
081     * @author Juan A. Recio-Garcia
082     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
083     * @version 1.0
084     */
085    public class Houses9 implements StandardCBRApplication
086    {
087        /** Connector object */
088        Connector _connector;
089        /** CaseBase object */
090        CBRCaseBase _caseBase;
091    
092        /** KNN configuration*/
093        NNConfig simConfig;
094        
095        /** Obtain query configuration*/
096        Collection<Attribute> hiddenAtts;
097        /** Obtain query configuration*/
098        Map<Attribute,String> labels;
099        
100        /** Critiques configuration object */
101        Collection<CritiqueOption> critiques;
102        
103        public void configure() throws ExecutionException
104        {
105            // Create a data base connector
106            _connector = new PlainTextConnector();
107            // Init the ddbb connector with the config file
108            _connector.initFromXMLfile(jcolibri.util.FileIO
109                            .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml"));
110            // Create a Lineal case base for in-memory organization
111            _caseBase = new LinealCaseBase();
112            
113            //Lets configure the KNN
114            simConfig = new NNConfig();
115            // Set the average() global similarity function for the description of the case
116            simConfig.setDescriptionSimFunction(new Average());
117            simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv"));
118            simConfig.addMapping(new Attribute("beds", HouseDescription.class), new InrecaMoreIsBetter(0.5));
119            simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5));
120            simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal());
121            simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal());
122            simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5));
123    
124    
125            // Obtain query configuration
126            hiddenAtts = new ArrayList<Attribute>();
127            labels = new HashMap<Attribute,String>();
128            labels.put(new Attribute("beds", HouseDescription.class), "Min bedrooms");
129            labels.put(new Attribute("price", HouseDescription.class), "Max price");
130            labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms");
131            
132            // Critiques configuration
133            critiques = new ArrayList<CritiqueOption>();
134            critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess()));
135            critiques.add(new CritiqueOption("Cheaper",new Attribute("price", HouseDescription.class),new QueryMore()));
136            critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess()));
137            critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()));
138            critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual()));
139        }
140    
141        public void cycle(CBRQuery query) throws ExecutionException
142        {   
143            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(_caseBase.getCases(), critiques, _caseBase.getCases());
144    
145            // Jump to main conversation
146            sequence1(choice.getSelectedCaseAsQuery(),choice.getFilterConfig());
147    
148        }
149        
150        
151        public void sequence1(CBRQuery query, FilterConfig filterConfig)  throws ExecutionException
152        {   
153            // Execute Filter
154            Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig);
155            
156            // Execute NN
157            Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig);
158            
159            // Select cases
160            Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 10);
161            
162            // Obtain critizied query
163            CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases());
164            
165            if(ContinueOrFinish.continueOrFinish(choice))
166                sequence2(choice.getSelectedCaseAsQuery(), choice);
167            else
168                sequence3(choice, selectedCases);
169        }
170        
171        public void sequence2(CBRQuery query, CriticalUserChoice cuc) throws ExecutionException
172        {
173            // Replaze current query with the critizied one
174            MoreLikeThis.moreLikeThis(query, cuc.getSelectedCase());
175            
176            sequence1(query, cuc.getFilterConfig());
177        }
178        
179        public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases)  throws ExecutionException
180        {
181            if(BuyOrQuit.buyOrQuit(choice))
182                System.out.println("Finish - User Buys: "+choice.getSelectedCase());
183            
184            else
185                System.out.println("Finish - User Quits");
186        }
187    
188        public void postCycle() throws ExecutionException
189        {
190        }
191    
192        public CBRCaseBase preCycle() throws ExecutionException
193        {
194            // Load cases from connector into the case base
195            _caseBase.init(_connector);             
196            // Print the cases
197            java.util.Collection<CBRCase> cases = _caseBase.getCases();
198            for(CBRCase c: cases)
199                    System.out.println(c);
200            return _caseBase;
201        }
202        
203        public static void main(String[] args) {
204            StandardCBRApplication recommender = new Houses9();
205            try
206            {
207                recommender.configure();
208                
209                recommender.preCycle();
210                
211                CBRQuery query = new CBRQuery();
212                
213                HouseDescription hd = new HouseDescription();
214                
215                query.setDescription(hd);
216                
217                recommender.cycle(query);
218                
219                recommender.postCycle();
220                
221                //System.exit(0);
222            } catch (Exception e)
223            {
224                org.apache.commons.logging.LogFactory.getLog(Houses9.class).error(e);
225                
226            }
227            
228    
229        }
230    
231    }