001 /** 002 * Houses13.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.rec13; 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.conditionals.DisplayCasesIfNumber; 029 import jcolibri.extensions.recommendation.navigationByProposing.CriticalUserChoice; 030 import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption; 031 import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod; 032 import jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis; 033 import jcolibri.extensions.recommendation.tabuList.TabuList; 034 import jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod; 035 import jcolibri.method.retrieve.RetrievalResult; 036 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod; 037 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig; 038 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual; 039 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess; 040 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore; 041 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMoreOrEqual; 042 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Threshold; 043 import jcolibri.method.retrieve.NNretrieval.NNConfig; 044 import jcolibri.method.retrieve.NNretrieval.NNScoringMethod; 045 import jcolibri.method.retrieve.NNretrieval.similarity.global.Average; 046 import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal; 047 import jcolibri.method.retrieve.NNretrieval.similarity.local.Table; 048 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaLessIsBetter; 049 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter; 050 import jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection; 051 import jcolibri.test.recommenders.housesData.HouseDescription; 052 053 /** 054 * Conversational (type B) flats recommender using Navigation by Proposing and Filtering + Nearest Neighbour + Compromise Driven Selection. 055 * <br> 056 * This recommender follows the Navigation by Proposing strategy with two important features: it uses Compromise Driven selection after 057 * the NN scoring and it manages a tabu list of prevously displayed items. 058 * <br> 059 * The compromise driven selection method chooses cases according to their compromises with the user's query. 060 * See {@link jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection} for details. 061 * <br> 062 * The tabu list avoids displaying again an item that has been already presented to the user. 063 * See {@link jcolibri.extensions.recommendation.tabuList.TabuList} for details. 064 * <br>Summary: 065 * <ul> 066 * <li>Type: Conversational B 067 * <li>Case base: houses 068 * <li>One off Preference Elicitation: Form filling (with initial values) 069 * <li>Retrieval: Filtered + KNN + Compromise Driven selection 070 * <li>Display: In table with critiques 071 * <li>Iterated Preference Elecitiation: Navigation by Proposing: MLT. 072 * </ul> 073 * This recommender implements the following template:<br> 074 * <center><img src="../Template11_Cycle.jpg"/></center> 075 * 076 * <br>Read the documentation of the recommenders extension for details about templates 077 * and recommender strategies: {@link jcolibri.extensions.recommendation} 078 * 079 * @see jcolibri.method.gui.formFilling.ObtainQueryWithFormMethod 080 * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod 081 * @see jcolibri.method.retrieve.NNretrieval.NNScoringMethod 082 * @see jcolibri.method.retrieve.selection.compromiseDriven.CompromiseDrivenSelection 083 * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod 084 * @see jcolibri.extensions.recommendation.navigationByProposing.queryElicitation.MoreLikeThis 085 * 086 * 087 * @author Juan A. Recio-Garcia 088 * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge. 089 * @version 1.0 090 */ 091 public class Houses13 implements StandardCBRApplication 092 { 093 /** Connector object */ 094 Connector _connector; 095 /** CaseBase object */ 096 CBRCaseBase _caseBase; 097 098 /** NN configuration*/ 099 NNConfig simConfig; 100 101 /** Obtain query configuration*/ 102 Collection<Attribute> hiddenAtts; 103 /** Obtain query configuration*/ 104 Map<Attribute,String> labels; 105 106 /** Critiques configuration object */ 107 Collection<CritiqueOption> critiques; 108 109 /** CDR configuration */ 110 FilterConfig preferences; 111 112 public void configure() throws ExecutionException 113 { 114 // Create a data base connector 115 _connector = new PlainTextConnector(); 116 // Init the ddbb connector with the config file 117 _connector.initFromXMLfile(jcolibri.util.FileIO 118 .findFile("jcolibri/test/recommenders/housesData/plaintextconfig.xml")); 119 // Create a Lineal case base for in-memory organization 120 _caseBase = new LinealCaseBase(); 121 122 //Lets configure the KNN 123 simConfig = new NNConfig(); 124 // Set the average() global similarity function for the description of the case 125 simConfig.setDescriptionSimFunction(new Average()); 126 simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv")); 127 simConfig.addMapping(new Attribute("beds", HouseDescription.class), new InrecaMoreIsBetter(0.5)); 128 simConfig.addMapping(new Attribute("price", HouseDescription.class), new InrecaLessIsBetter(2000, 0.5)); 129 simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new Equal()); 130 simConfig.addMapping(new Attribute("type", HouseDescription.class), new Equal()); 131 simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5)); 132 133 134 // Obtain query configuration 135 hiddenAtts = new ArrayList<Attribute>(); 136 labels = new HashMap<Attribute,String>(); 137 labels.put(new Attribute("beds", HouseDescription.class), "Min bedrooms"); 138 labels.put(new Attribute("price", HouseDescription.class), "Approximate price"); 139 labels.put(new Attribute("baths", HouseDescription.class), "Min bahtrooms"); 140 141 // Critiques configuration 142 critiques = new ArrayList<CritiqueOption>(); 143 critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess())); 144 critiques.add(new CritiqueOption("Cheaper",new Attribute("price", HouseDescription.class),new QueryMore())); 145 critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess())); 146 critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal())); 147 critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual())); 148 149 preferences = new FilterConfig(); 150 preferences.addPredicate(new Attribute("beds", HouseDescription.class), new QueryMoreOrEqual()); 151 preferences.addPredicate(new Attribute("price", HouseDescription.class), new Threshold(50)); 152 preferences.addPredicate(new Attribute("baths", HouseDescription.class), new QueryMoreOrEqual()); 153 preferences.addPredicate(new Attribute("furnished", HouseDescription.class), new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()); 154 preferences.addPredicate(new Attribute("type", HouseDescription.class), new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal()); 155 156 } 157 158 public void cycle(CBRQuery query) throws ExecutionException 159 { 160 // Obtain query with form filling 161 ObtainQueryWithFormMethod.obtainQueryWithInitialValues(query, hiddenAtts,labels); 162 163 // Jump to main conversation 164 sequence1(query, new FilterConfig()); 165 166 } 167 168 169 public void sequence1(CBRQuery query, FilterConfig filterConfig) throws ExecutionException 170 { 171 // Execute Filter 172 Collection<CBRCase> filtered = FilterBasedRetrievalMethod.filterCases(_caseBase.getCases(), query, filterConfig); 173 174 // Execute NN 175 Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(filtered, query, simConfig); 176 177 // Select Cases 178 Collection<CBRCase> selectedCases = CompromiseDrivenSelection.CDR(query, retrievedCases, preferences); 179 180 // Remove cases in Tabu List 181 selectedCases = TabuList.removeTabuList(selectedCases); 182 183 if(DisplayCasesIfNumber.displayCasesWithMessage(Integer.MAX_VALUE, 1, selectedCases)) 184 sequence2(selectedCases); 185 else 186 System.exit(0); 187 188 } 189 190 public void sequence2(Collection<CBRCase> selectedCases) throws ExecutionException 191 { 192 // Obtain critizied query 193 CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, _caseBase.getCases()); 194 195 // Update Tabu list 196 TabuList.updateTabuList(selectedCases); 197 198 if(ContinueOrFinish.continueOrFinish(choice)) 199 sequence3(choice.getSelectedCaseAsQuery(), choice); 200 else 201 sequence4(choice, selectedCases); 202 203 } 204 205 public void sequence3(CBRQuery query, CriticalUserChoice cuc) throws ExecutionException 206 { 207 // Replaze current query with the critizied one 208 MoreLikeThis.moreLikeThis(query, cuc.getSelectedCase()); 209 210 sequence1(query, cuc.getFilterConfig()); 211 } 212 213 public void sequence4(UserChoice choice, Collection<CBRCase> retrievedCases) throws ExecutionException 214 { 215 if(BuyOrQuit.buyOrQuit(choice)) 216 System.out.println("Finish - User Buys: "+choice.getSelectedCase()); 217 218 else 219 System.out.println("Finish - User Quits"); 220 } 221 222 public void postCycle() throws ExecutionException 223 { 224 } 225 226 public CBRCaseBase preCycle() throws ExecutionException 227 { 228 // Load cases from connector into the case base 229 _caseBase.init(_connector); 230 // Print the cases 231 java.util.Collection<CBRCase> cases = _caseBase.getCases(); 232 for(CBRCase c: cases) 233 System.out.println(c); 234 return _caseBase; 235 } 236 237 public static void main(String[] args) { 238 StandardCBRApplication recommender = new Houses13(); 239 try 240 { 241 recommender.configure(); 242 243 recommender.preCycle(); 244 245 CBRQuery query = new CBRQuery(); 246 247 HouseDescription hd = new HouseDescription(); 248 hd.setArea(HouseDescription.Area.Hampstead); 249 hd.setBaths(1); 250 hd.setBeds(HouseDescription.Beds.two); 251 hd.setFurnished(true); 252 hd.setPrice(500); 253 hd.setType(HouseDescription.Type.Flat); 254 query.setDescription(hd); 255 256 recommender.cycle(query); 257 258 recommender.postCycle(); 259 260 //System.exit(0); 261 } catch (Exception e) 262 { 263 org.apache.commons.logging.LogFactory.getLog(Houses13.class).error(e); 264 265 } 266 267 268 } 269 270 }