001    /**
002     * Test1.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     * 28/11/2006
008     */
009    package jcolibri.test.test1;
010    
011    import java.util.Collection;
012    
013    import jcolibri.casebase.LinealCaseBase;
014    import jcolibri.cbraplications.StandardCBRApplication;
015    import jcolibri.cbrcore.Attribute;
016    import jcolibri.cbrcore.CBRCase;
017    import jcolibri.cbrcore.CBRCaseBase;
018    import jcolibri.cbrcore.CBRQuery;
019    import jcolibri.cbrcore.Connector;
020    import jcolibri.connector.DataBaseConnector;
021    import jcolibri.exception.ExecutionException;
022    import jcolibri.method.retrieve.RetrievalResult;
023    import jcolibri.method.retrieve.NNretrieval.NNConfig;
024    import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
025    import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
026    import jcolibri.method.retrieve.NNretrieval.similarity.local.Equal;
027    import jcolibri.method.retrieve.NNretrieval.similarity.local.Interval;
028    import jcolibri.method.retrieve.selection.SelectCases;
029    
030    /**
031     * Test 1 shows how to use a simple data base connector and perform the KNN retrieval. It uses the travel example with cases that only have description
032     * (without solution or result).
033     * <br>
034     * This example uses the DataBase connector that is implemented using the <a href="www.hibernate.org">Hibernate</a> library. 
035     * That library is a Java Data Objects implementation that automatically manages the persistence of 
036     * Java beans in relational data bases.
037     * <br>For an introduction to hibernate see: <a href="http://www.hibernate.org/hib_docs/v3/reference/en/html/tutorial.html">http://www.hibernate.org/hib_docs/v3/reference/en/html/tutorial.html</a>
038     * <p> 
039     * The DataBase connector in jcolibri/test/test1/databaseconfig.xml and that xml defines the configuration of Hibernate and
040     * the mapping of the description of our case with the data base. In this example, all the attributes of the description bean are stored in the same table.
041     * <br>
042     * <ul>
043     * <li><b>databaseconfig.xml</b>.<br>Connector configuration file: indicates the path to the hibernate config file, the name of the class/bean that stores the description and its mapping file.<br>
044     * <pre>
045     * &lt;DataBaseConfiguration&gt;
046     *        &lt;HibernateConfigFile&gt;jcolibri/test/test1/hibernate.cfg.xml&lt;/HibernateConfigFile&gt;
047     *        &lt;DescriptionMappingFile&gt;jcolibri/test/test1/TravelDescription.hbm.xml&lt;/DescriptionMappingFile&gt;
048     *        &lt;DescriptionClassName&gt;jcolibri.test.test1.TravelDescription&lt;/DescriptionClassName&gt;
049     * &lt;/DataBaseConfiguration&gt;
050     * </pre>
051     * 
052     * <li><b>hibernate.cfg.xml</b>.<br>Hibernate configuration file: developers should only modify the database connection settings.<br>
053     * <pre>
054     * &lt;hibernate-configuration&gt;
055     *   &lt;session-factory&gt;
056     *       &lt;!-- Database connection settings --&gt;
057     *       &lt;property name="connection.driver_class"&gt;org.hsqldb.jdbcDriver&lt;/property&gt;
058     *       &lt;property name="connection.url"&gt;jdbc:hsqldb:hsql://localhost/travel&lt;/property&gt;
059     *       &lt;property name="connection.username"&gt;sa&lt;/property&gt;
060     *       &lt;property name="connection.password"&gt;&lt;/property&gt;
061     *              
062     *       &lt;!-- JDBC connection pool (use the built-in) --&gt;
063     *       &lt;property name="connection.pool_size"&gt;1&lt;/property&gt;
064     *
065     *       &lt;!-- SQL dialect --&gt;
066     *       &lt;property name="dialect"&gt;org.hibernate.dialect.HSQLDialect&lt;/property&gt;
067     *
068     *       &lt;!-- Enable Hibernate's automatic session context management --&gt;
069     *       &lt;property name="current_session_context_class"&gt;thread&lt;/property&gt;
070     *
071     *       &lt;!-- Disable the second-level cache  --&gt;
072     *       &lt;property name="cache.provider_class"&gt;org.hibernate.cache.NoCacheProvider&lt;/property&gt;
073     *
074     *       &lt;!-- Echo all executed SQL to stdout --&gt;
075     *      &lt;property name="show_sql"&gt;true&lt;/property&gt;   
076     *    &lt;/session-factory&gt;
077     * &lt;/hibernate-configuration&gt;
078     * </pre>
079     * <p>This test uses the HSQLDB data base server with an example table containing 
080     * the data of the case base. Developers can use any other DBMS changing the 
081     * hibernate configuration file.
082     * <br>
083     * If you use another database change the driver, url and dialect fields. 
084     * For example, to use a MySQL server you should use:
085     * <pre>
086     *       &lt;property name="connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/property&gt;
087     *       &lt;property name="connection.url"&gt;jdbc:mysql://localhost:3306/travel&lt;/property&gt;
088     *       &lt;property name="dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt;
089     * </pre>
090     * For other configuration settings see hiberante documentation: 
091     * <a href="http://www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html">http://www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html</a>
092     * </p>
093     * </li>
094     * <li><b>TravelDescription.hbm.xml</b>.<br> Hibernate mapping file for the description bean the case (TravelDescription.java).
095     * It stores each attribute of the description in a column of the table Travel.<br>
096     * <pre>
097     * &lt;hibernate-mapping default-lazy="false"&gt;
098     *  &lt;class name="jcolibri.test.test1.TravelDescription" table="Travel"&gt;
099     *        &lt;id name="caseId" column="caseId"&gt;
100     *          &lt;generator class="native"/&gt;
101     *        &lt;/id&gt;
102     *        &lt;property name="HolidayType" column="HolidayType"/&gt;
103     *        &lt;property name="Price" column="Price"/&gt;
104     *        &lt;property name="NumberOfPersons" column="NumberOfPersons"/&gt;
105     *        &lt;property name="Region" column="Region"/&gt;
106     *        &lt;property name="Transportation" column="Transportation"/&gt;
107     *        &lt;property name="Duration" column="Duration"/&gt;
108     *        &lt;property name="Season" column="Season"/&gt;
109     *        &lt;property name="Accomodation" column="Accommodation"/&gt;
110     *        &lt;property name="Hotel" column="Hotel"/&gt; 
111     *  &lt;/class&gt;
112     * &lt;/hibernate-mapping&gt;
113     * </pre>
114     * Here we set that TravelDescription is mapped in the Travel table. caseId is the primary key of the table and Hibernate will use a 
115     * native key generator for new cases (there are different ways to create primary keys, for more information see Hiberante documentation).
116     * Each attribute is mapped into a table with the same name. You should notice that here we don't indicate the type of the attributes. 
117     * Hibernate automatically detects the type and converts from/to the database. Anyway if you want to use an unrecognoized type that hibernate does not
118     * understand or create your own one you can do it by implementing the jcolibri.connector.TypeAdaptor interface in your type.
119     * <br>
120     * This is the structure of the table:
121     * <pre>
122     * +----------+-------------+-------+-----------------+--------+----------------+----------+--------+---------------+--------------------------+
123     * | caseId   | HolidayType | Price | NumberOfPersons | Region | Transportation | Duration | Season | Accommodation | Hotel                    |
124     * +----------+-------------+-------+-----------------+--------+----------------+----------+--------+---------------+--------------------------+
125     * | Journey1 | Bathing     |  2498 |               2 | Egypt  | Plane          |       14 | April  | TwoStars      | Hotel White House, Egypt |
126     * | Journey2 | Bathing     |  3066 |               3 | Egypt  | Plane          |       21 | May    | TwoStars      | Hotel White House, Egypt | 
127     * ...
128     * </pre>
129     * The travel.sql file contains the code to create this data base.
130     * </ul>
131     * 
132     * @author Juan A. Recio-Garcia
133     * @version 1.0
134     * @see jcolibri.test.test1.TravelDescription
135     * @see jcolibri.connector.DataBaseConnector
136     */
137    public class Test1 implements StandardCBRApplication {
138    
139            /** Connector object */
140            Connector _connector;
141            /** CaseBase object */
142            CBRCaseBase _caseBase;
143            
144            /* (non-Javadoc)
145             * @see jcolibri.cbraplications.BasicCBRApplication#configure()
146             */
147            public void configure() throws ExecutionException{
148                    try{
149                    // Create a data base connector
150                    _connector = new DataBaseConnector();
151                    // Init the ddbb connector with the config file
152                    _connector.initFromXMLfile(jcolibri.util.FileIO.findFile("jcolibri/test/test1/databaseconfig.xml"));
153                    // Create a Lineal case base for in-memory organization
154                    _caseBase  = new LinealCaseBase();
155                    } catch (Exception e){
156                            throw new ExecutionException(e);
157                    }
158            }
159    
160            
161            /* (non-Javadoc)
162             * @see jcolibri.cbraplications.BasicCBRApplication#preCycle()
163             */
164            public CBRCaseBase preCycle() throws ExecutionException {
165                    // Load cases from connector into the case base
166                    _caseBase.init(_connector);             
167                    // Print the cases
168                    java.util.Collection<CBRCase> cases = _caseBase.getCases();
169                    for(CBRCase c: cases)
170                            System.out.println(c);
171                    return _caseBase;
172            }
173            
174            /* (non-Javadoc)
175             * @see jcolibri.cbraplications.BasicCBRApplication#cycle()
176             */
177            public void cycle(CBRQuery query) throws ExecutionException 
178            {               
179                    // First configure the KNN
180                    NNConfig simConfig = new NNConfig();
181                    // Set the average() global similarity function for the description of the case
182                    simConfig.setDescriptionSimFunction(new Average());
183                    // The accomodation attribute uses the equal() local similarity function
184                    simConfig.addMapping(new Attribute("Accomodation", TravelDescription.class), new Equal());
185                    // For the duration attribute we are going to set its local similarity function and the weight
186                    Attribute duration = new Attribute("Duration", TravelDescription.class);
187                    simConfig.addMapping(duration, new Interval(31));
188                    simConfig.setWeight(duration, 0.5);
189                    // HolidayType --> equal()
190                    simConfig.addMapping(new Attribute("HolidayType", TravelDescription.class), new Equal());
191                    // NumberOfPersons --> equal()
192                    simConfig.addMapping(new Attribute("NumberOfPersons", TravelDescription.class), new Equal());
193                    // Price --> InrecaLessIsBetter()
194                    simConfig.addMapping(new Attribute("Price", TravelDescription.class), new Interval(4000));
195                    
196                    
197                    // A bit of verbose
198                    System.out.println("Query Description:");
199                    System.out.println(query.getDescription());
200                    System.out.println();
201                    
202                    // Execute NN
203                    Collection<RetrievalResult> eval = NNScoringMethod.evaluateSimilarity(_caseBase.getCases(), query, simConfig);
204                    
205                    // Select k cases
206                    eval = SelectCases.selectTopKRR(eval, 5);
207                    
208                    // Print the retrieval
209                    System.out.println("Retrieved cases:");
210                    for(RetrievalResult nse: eval)
211                            System.out.println(nse);
212                    
213    
214            }
215    
216            /* (non-Javadoc)
217             * @see jcolibri.cbraplications.BasicCBRApplication#postCycle()
218             */
219            public void postCycle() throws ExecutionException {
220                    this._caseBase.close();
221    
222            }
223    
224            /**
225             * Main function
226             */
227            public static void main(String[] args) {
228                    // Launch DDBB manager
229                    jcolibri.test.database.HSQLDBserver.init();
230                    // Create the application
231                    Test1 test1 = new Test1();
232                    try {
233                            // Configure it
234                            test1.configure();
235                            // Run the precycle --> load the cases
236                            test1.preCycle();
237                            
238                            //BufferedReader reader  = new BufferedReader(new InputStreamReader(System.in));                        
239                            //do
240                            {               
241                                    // Configure the query. Queries only have description.
242                                    TravelDescription queryDesc = new TravelDescription();
243                                    queryDesc.setAccomodation("ThreeStars");
244                                    queryDesc.setDuration(7);
245                                    queryDesc.setHolidayType("Recreation");
246                                    queryDesc.setNumberOfPersons(2);
247                                    queryDesc.setPrice(700);
248                                    
249                                    CBRQuery query = new CBRQuery();
250                                    query.setDescription(queryDesc);
251                                    
252                                    // Run a cycle with the query
253                                    test1.cycle(query);
254                                    
255                                    System.out.println("Cycle finished. Type exit to idem or enter to repeat the cycle");
256                            }
257                            //while(!reader.readLine().equals("exit"));
258                            
259                            // Run the postcycle
260                            test1.postCycle();
261    
262                            //Shutdown DDBB manager
263                            jcolibri.test.database.HSQLDBserver.shutDown();
264                    } catch (Exception e) {
265                            System.out.println(e.getMessage());
266                            e.printStackTrace();
267                    }
268            }
269    
270    }