001 /** 002 * Houses6.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.rec6; 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.gui.formFilling.ObtainQueryWithFormMethod; 033 import jcolibri.method.retrieve.RetrievalResult; 034 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod; 035 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig; 036 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual; 037 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess; 038 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore; 039 import jcolibri.method.retrieve.NNretrieval.NNConfig; 040 import jcolibri.method.retrieve.NNretrieval.NNScoringMethod; 041 import jcolibri.method.retrieve.NNretrieval.similarity.global.Average; 042 import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal; 043 import jcolibri.method.retrieve.NNretrieval.similarity.local.Table; 044 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter; 045 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter; 046 import jcolibri.method.retrieve.selection.SelectCases; 047 import jcolibri.test.recommenders.housesData.HouseDescription; 048 049 /** 050 * Conversational (type A) flats recommender using Navigation by Proposing and Filtered+NearestNeighbour+topKselection retrieval. 051 * <br> 052 * This recommender implements the Navigation by Proposing strategy. 053 * This strategy selects and displays some items to the user and the he/she makes 054 * a critique over one of the displayed items (i.e.: "like this but cheaper"). 055 * To obtain the user preferences this recommender uses a form. Then, the filtering method 056 * is executed using as filters the critiques over the previously presented items. Finally, the 057 * Nearest Neighbour method is applied to the filtered set to obtain the items displayed 058 * to the user. 059 * <br>Summary: 060 * <ul> 061 * <li>Type: Conversational A 062 * <li>Case base: houses 063 * <li>One off Preference Elicitation: Form filling (without initial values) 064 * <li>Retrieval: Filtering + NN + topKselection 065 * <li>Display: In table with critiques 066 * <li>Iterated Preference Elecitiation: Navigation by Proposing: More Like This. 067 * </ul> 068 * This recommender implements the following template:<br> 069 * <center><img src="../Template6_Cycle.jpg"/></center> 070 * 071 * <br>Read the documentation of the recommenders extension for details about templates 072 * and recommender strategies: {@link jcolibri.extensions.recommendation} 073 * 074 * @see jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod 075 * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod 076 * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod 077 * @see jcolibri.method.retrieve.selection.SelectCases 078 * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod 079 * @see jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis 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 Houses6 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 126 // Obtain query configuration 127 hiddenAtts = new ArrayList<Attribute>(); 128 labels = new HashMap<Attribute,String>(); 129 labels.put(new Attribute("beds", HouseDescription.class), "Min bedrooms"); 130 labels.put(new Attribute("price", HouseDescription.class), "Max price"); 131 labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms"); 132 133 // Critiques configuration 134 critiques = new ArrayList<CritiqueOption>(); 135 critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess())); 136 critiques.add(new CritiqueOption("Cheaper",new Attribute("price", HouseDescription.class),new QueryMore())); 137 critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess())); 138 critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal())); 139 critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual())); 140 } 141 142 public void cycle(CBRQuery query) throws ExecutionException 143 { 144 // Obtain query with form filling 145 ObtainQueryWithFormMethod.obtainQueryWithoutInitialValues(query,hiddenAtts,labels); 146 147 // Jump to main conversation 148 sequence1(query, new FilterConfig()); 149 150 } 151 152 153 public void sequence1(CBRQuery query, FilterConfig filterConfig) throws ExecutionException 154 { 155 // Execute Filter 156 Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig); 157 158 // Execute NN 159 Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig); 160 161 // Select cases 162 Collection<CBRCase> selectedCases = SelectCases.selectTopK(retrievedCases, 10); 163 164 // Obtain critizied query 165 CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases()); 166 167 if(ContinueOrFinish.continueOrFinish(choice)) 168 sequence2(choice.getSelectedCaseAsQuery(), choice); 169 else 170 sequence3(choice, selectedCases); 171 } 172 173 public void sequence2(CBRQuery query, CriticalUserChoice cuc) throws ExecutionException 174 { 175 // Replaze current query with the critizied one 176 MoreLikeThis.moreLikeThis(query, cuc.getSelectedCase()); 177 sequence1(query, cuc.getFilterConfig()); 178 } 179 180 public void sequence3(UserChoice choice, Collection<CBRCase> retrievedCases) throws ExecutionException 181 { 182 if(BuyOrQuit.buyOrQuit(choice)) 183 System.out.println("Finish - User Buys: "+choice.getSelectedCase()); 184 185 else 186 System.out.println("Finish - User Quits"); 187 } 188 189 public void postCycle() throws ExecutionException 190 { 191 } 192 193 public CBRCaseBase preCycle() throws ExecutionException 194 { 195 // Load cases from connector into the case base 196 _caseBase.init(_connector); 197 // Print the cases 198 java.util.Collection<CBRCase> cases = _caseBase.getCases(); 199 for(CBRCase c: cases) 200 System.out.println(c); 201 return _caseBase; 202 } 203 204 public static void main(String[] args) { 205 StandardCBRApplication recommender = new Houses6(); 206 try 207 { 208 recommender.configure(); 209 210 recommender.preCycle(); 211 212 CBRQuery query = new CBRQuery(); 213 214 HouseDescription hd = new HouseDescription(); 215 216 query.setDescription(hd); 217 218 recommender.cycle(query); 219 220 recommender.postCycle(); 221 222 //System.exit(0); 223 } catch (Exception e) 224 { 225 org.apache.commons.logging.LogFactory.getLog(Houses6.class).error(e); 226 227 } 228 229 230 } 231 232 }