001 /** 002 * Houses8.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.rec8; 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.askingAndProposing.AskingAndProposingPreferenceElicitation; 026 import jcolibri.extensions.recommendation.askingAndProposing.DisplayCasesIfNumberAndChangeNavigation; 027 import jcolibri.extensions.recommendation.casesDisplay.UserChoice; 028 import jcolibri.extensions.recommendation.conditionals.BuyOrQuit; 029 import jcolibri.extensions.recommendation.conditionals.ContinueOrFinish; 030 import jcolibri.extensions.recommendation.navigationByAsking.InformationGain; 031 import jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod; 032 import jcolibri.extensions.recommendation.navigationByAsking.SelectAttributeMethod; 033 import jcolibri.extensions.recommendation.navigationByProposing.CriticalUserChoice; 034 import jcolibri.extensions.recommendation.navigationByProposing.CritiqueOption; 035 import jcolibri.extensions.recommendation.navigationByProposing.DisplayCasesTableWithCritiquesMethod; 036 import jcolibri.method.retrieve.RetrievalResult; 037 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod; 038 import jcolibri.method.retrieve.FilterBasedRetrieval.FilterConfig; 039 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal; 040 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.NotEqual; 041 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryLess; 042 import jcolibri.method.retrieve.FilterBasedRetrieval.predicates.QueryMore; 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.EnumDistance; 047 import jcolibri.method.retrieve.NNretrieval.similarity.local.Table; 048 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.InrecaMoreIsBetter; 049 import jcolibri.method.retrieve.NNretrieval.similarity.local.recommenders.McSherryMoreIsBetter; 050 import jcolibri.method.retrieve.selection.diversity.BoundedGreedySelection; 051 import jcolibri.test.recommenders.rec8.housesData.HouseDescription; 052 053 /** 054 * Conversational (type B) flats recommender using both Navigation by Asking and Navigation by Proposing. 055 * <br> 056 * This example reproduces the behaviour of the ExpertClerk system. It works as a Navigation by Asking system until the number 057 * of cases is small enough and then it changes to Navigation by Proposing. 058 * <p>See: 059 * <p> 060 * H. Shimazu. ExpertClerk: A Conversational Case-Based Reasoning Tool for 061 * Developing Salesclerk Agents in E-Commerce Webshops. Artif. Intell. Rev., 062 * 18(3-4):223-244, 2002. 063 * <p> 064 * <br>Summary: 065 * <ul> 066 * <li>Type: Conversational B. 067 * <li>Case base: houses2 (price moved to the solution and priceRange in the description). 068 * <li>One off Preference Elicitation: Navigation by Asking using Information Gain. 069 * <li>Retrieval: Filter-Based 070 * <li>Display Condition: number of cases. If the number of cases is less than a value it changes the Iterated Preference Elicitation to NbP 071 * <li>Display: In table with critiques. (Cases are only shown in NbP mode) 072 * <li>Iterated Preference Elicitation: Depends on the mode. The method AskingAndProposingPreferenceElicitation selects an attribute 073 * using InformationGain in NbA mode or simply replaces current query with the critizied one in NbP. 074 * </ul> 075 * This recommender implements the following template:<br> 076 * <center><img src="../Template8_Cycle.jpg"/></center> 077 * 078 * <br>Read the documentation of the recommenders extension for details about templates 079 * and recommender strategies: {@link jcolibri.extensions.recommendation} 080 * 081 * @see jcolibri.extensions.recommendation.navigationByAsking.ObtainQueryWithAttributeQuestionMethod 082 * @see jcolibri.extensions.recommendation.navigationByAsking.InformationGain 083 * @see jcolibri.method.retrieve.FilterBasedRetrieval.FilterBasedRetrievalMethod 084 * @see jcolibri.extensions.recommendation.casesDisplay.DisplayCasesTableMethod 085 * @see jcolibri.extensions.recommendation.askingAndProposing.DisplayCasesIfNumberAndChangeNavigation 086 * @see jcolibri.method.retrieve.selection.diversity.BoundedGreedySelection 087 * 088 * @author Juan A. Recio-Garcia 089 * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge. 090 * @version 1.0 091 */ 092 public class Houses8 implements StandardCBRApplication 093 { 094 /** Connector object */ 095 Connector _connector; 096 /** CaseBase object */ 097 CBRCaseBase _caseBase; 098 099 FilterConfig filterConfig; 100 NNConfig simConfig; 101 SelectAttributeMethod selectAttributeMethod; 102 Collection<CritiqueOption> critiques; 103 104 public void configure() throws ExecutionException 105 { 106 // Create a data base connector 107 _connector = new PlainTextConnector(); 108 // Init the ddbb connector with the config file 109 _connector.initFromXMLfile(jcolibri.util.FileIO 110 .findFile("jcolibri/test/recommenders/rec8/housesData/plaintextconfig.xml")); 111 // Create a Lineal case base for in-memory organization 112 _caseBase = new LinealCaseBase(); 113 114 115 filterConfig = new FilterConfig(); 116 filterConfig.addPredicate(new Attribute("area", HouseDescription.class), new Equal()); 117 filterConfig.addPredicate(new Attribute("beds", HouseDescription.class), new Equal()); 118 filterConfig.addPredicate(new Attribute("priceRange", HouseDescription.class), new Equal()); 119 filterConfig.addPredicate(new Attribute("furnished", HouseDescription.class), new Equal()); 120 filterConfig.addPredicate(new Attribute("type", HouseDescription.class), new Equal()); 121 filterConfig.addPredicate(new Attribute("baths", HouseDescription.class), new Equal()); 122 123 //Lets configure the KNN 124 simConfig = new NNConfig(); 125 // Set the average() global similarity function for the description of the case 126 simConfig.setDescriptionSimFunction(new Average()); 127 simConfig.addMapping(new Attribute("area", HouseDescription.class), new Table("jcolibri/test/recommenders/housesData/area.csv")); 128 simConfig.addMapping(new Attribute("beds", HouseDescription.class), new McSherryMoreIsBetter(0,0)); 129 simConfig.addMapping(new Attribute("priceRange", HouseDescription.class), new EnumDistance()); 130 simConfig.addMapping(new Attribute("furnished", HouseDescription.class), new jcolibri.method.retrieve.NNretrieval.similarity.local.Equal()); 131 simConfig.addMapping(new Attribute("type", HouseDescription.class), new jcolibri.method.retrieve.NNretrieval.similarity.local.Equal()); 132 simConfig.addMapping(new Attribute("baths", HouseDescription.class), new InrecaMoreIsBetter(0.5)); 133 134 selectAttributeMethod = new InformationGain(_caseBase.getCases()); 135 136 137 critiques = new ArrayList<CritiqueOption>(); 138 critiques.add(new CritiqueOption("More Beds",new Attribute("beds", HouseDescription.class),new QueryLess())); 139 critiques.add(new CritiqueOption("Cheaper",new Attribute("priceRange", HouseDescription.class),new QueryMore())); 140 critiques.add(new CritiqueOption("More Bathrooms",new Attribute("baths", HouseDescription.class),new QueryLess())); 141 critiques.add(new CritiqueOption("Change Area",new Attribute("area", HouseDescription.class),new jcolibri.method.retrieve.FilterBasedRetrieval.predicates.Equal())); 142 critiques.add(new CritiqueOption("Another Area",new Attribute("area", HouseDescription.class),new NotEqual())); 143 144 145 } 146 147 public void cycle(CBRQuery query) throws ExecutionException 148 { 149 Attribute att = selectAttributeMethod.getAttribute(_caseBase.getCases(), query); 150 151 Map<Attribute,String> labels = new HashMap<Attribute,String>(); 152 ObtainQueryWithAttributeQuestionMethod.obtainQueryWithAttributeQuestion(query, att, labels, _caseBase.getCases()); 153 154 sequence1(query, _caseBase.getCases(), filterConfig); 155 156 } 157 158 159 public void sequence1(CBRQuery query, Collection<CBRCase> cases, FilterConfig fc) throws ExecutionException 160 { 161 Collection<CBRCase> workingCases = FilterBasedRetrievalMethod.filterCases(cases, query, fc); 162 163 if(DisplayCasesIfNumberAndChangeNavigation.displayCasesIfNumberAndChangeNavigation(50, workingCases)) 164 sequence2(query, workingCases); 165 else 166 sequence3(query, workingCases, null); 167 } 168 169 public void sequence2(CBRQuery query, Collection<CBRCase> workingCases) throws ExecutionException 170 { 171 Collection<RetrievalResult> retrievedCases = NNScoringMethod.evaluateSimilarity(workingCases, query, simConfig); 172 173 Collection<CBRCase> selectedCases = BoundedGreedySelection.boundedGreddySelection(retrievedCases, query, simConfig,3,3); 174 175 CriticalUserChoice choice = DisplayCasesTableWithCritiquesMethod.displayCasesInTableWithCritiques(selectedCases, critiques, workingCases); 176 177 if(ContinueOrFinish.continueOrFinish(choice)) 178 sequence3(query,workingCases, choice); 179 else 180 sequence4(choice, workingCases); 181 } 182 183 public void sequence3(CBRQuery query, Collection<CBRCase> workingCases, CriticalUserChoice choice) throws ExecutionException 184 { 185 AskingAndProposingPreferenceElicitation.doPreferenceElicitation(query, workingCases, selectAttributeMethod, choice); 186 if(choice != null) 187 sequence1(query, workingCases, choice.getFilterConfig()); 188 else 189 sequence1(query, workingCases, filterConfig); 190 } 191 192 public void sequence4(UserChoice choice, Collection<CBRCase> workingCases) throws ExecutionException 193 { 194 if(BuyOrQuit.buyOrQuit(choice)) 195 System.out.println("Finish - User Buys: "+choice.getSelectedCase()); 196 197 else 198 System.out.println("Finish - User Quits"); 199 } 200 201 public void postCycle() throws ExecutionException 202 { 203 } 204 205 public CBRCaseBase preCycle() throws ExecutionException 206 { 207 // Load cases from connector into the case base 208 _caseBase.init(_connector); 209 // Print the cases 210 java.util.Collection<CBRCase> cases = _caseBase.getCases(); 211 for(CBRCase c: cases) 212 System.out.println(c); 213 return _caseBase; 214 } 215 216 public static void main(String[] args) { 217 StandardCBRApplication recommender = new Houses8(); 218 try 219 { 220 recommender.configure(); 221 222 recommender.preCycle(); 223 224 CBRQuery query = new CBRQuery(); 225 226 HouseDescription hd = new HouseDescription(); 227 //hd.setArea("Hampstead"); 228 //hd.setBaths(1); 229 //hd.setBeds(HouseDescription.Beds.two); 230 //hd.setFurnished(true); 231 //hd.setPrice(500); 232 //hd.setType(HouseDescription.Type.Flat); 233 234 query.setDescription(hd); 235 236 recommender.cycle(query); 237 238 //System.exit(0); 239 } catch (Exception e) 240 { 241 org.apache.commons.logging.LogFactory.getLog(Houses8.class).error(e); 242 243 } 244 245 246 } 247 248 }