001: /*
002: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package org.mandarax.examples.db;
019:
020: import java.io.File;
021: import java.util.Date;
022:
023: import org.mandarax.kernel.Fact;
024: import org.mandarax.kernel.KnowledgeBase;
025: import org.mandarax.kernel.Rule;
026: import org.mandarax.kernel.SimplePredicate;
027: import org.mandarax.lib.math.DoubleArithmetic;
028: import org.mandarax.lib.math.IntArithmetic;
029: import org.mandarax.reference.AdvancedKnowledgeBase;
030: import org.mandarax.sql.OneColumnMapping;
031: import org.mandarax.sql.SQLFunction;
032: import org.mandarax.util.LogicFactorySupport;
033: import org.mandarax.zkb.*;
034: import org.mandarax.zkb.framework.ZKBDriver_1_1;
035:
036: /**
037: * This class creates the knowledge base for the discount example. To generate the knowledge base, run the main method.
038: * <p>
039: * Note that the example works with a relational database. Any database should do as long as aggregation
040: * functions are supported. E.g., the free MySQL database or Oracle8 can be used.
041: * The example uses a <code>SimpleDataSource</code> to connect to the database.
042: * How to configure a particular database is described in the comment of this class.
043: * <p>
044: * In a real world scenario a knowledge base is probably created using a GUI and not by the direct execution
045: * of a script as it is done here.
046: * <p>
047: * Mandarax uses other (open source) libraries such as JDOM, the apache log4j
048: * logging library and the junit testing framework. The mandarax distribution
049: * contains the respective libraries. Please but these jar files in the classpath
050: * before running the example! In addition, the JDBC driver for the database used must
051: * also be in the classpath.
052: * @see SimpleDataSource
053: * @see CreateDB
054: * @since 2.2
055: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
056: * @version 3.4 <7 March 05>
057: */
058: public class CreateKB {
059:
060: private LogicFactorySupport lfs = new LogicFactorySupport();
061:
062: // queries for functions
063: public static final String QUERY_MAX_AMOUNT_BY_CUSTOMER = "SELECT MAX(AMOUNT) FROM CUSTOMER_TRANSACTIONS WHERE CUSTOMER=? GROUP BY CUSTOMER";
064: public static final String QUERY_SUM_AMOUNT_BY_CUSTOMER = "SELECT SUM(AMOUNT) FROM CUSTOMER_TRANSACTIONS WHERE CUSTOMER=? GROUP BY CUSTOMER";
065: public static final String QUERY_NUMBER_OF_TRANSACTIONS_BY_CUSTOMER = "SELECT COUNT(*) FROM CUSTOMER_TRANSACTIONS WHERE CUSTOMER=?";
066: public static final String QUERY_DATE_OF_LAST_TRANSACTION_BY_CUSTOMER = "SELECT MAX(TRANSACTION_DATE) FROM CUSTOMER_TRANSACTIONS WHERE CUSTOMER=? GROUP BY CUSTOMER";
067:
068: // functions
069: public SQLFunction function_max_amount_by_customer = null;
070: public SQLFunction function_sum_amount_by_customer = null;
071: public SQLFunction function_number_transactions_by_customer = null;
072: public SQLFunction function_last_transaction_date_by_customer = null;
073:
074: // predicates
075: public SimplePredicate has_category = null;
076: public SimplePredicate gets_discount = null;
077:
078: /**
079: * Create the knowledge base.
080: */
081: public static void main(String[] args) {
082: // uncomment the following line to switch on logging
083: // org.apache.log4j.BasicConfigurator.configure();
084:
085: CreateKB kbCreator = new CreateKB();
086: kbCreator.initFunctionsAndPredicates();
087: KnowledgeBase kb = kbCreator.createKB();
088: kbCreator.saveKB(kb);
089: }
090:
091: /**
092: * Return the knowledge base for this example.
093: * @return a knowledge base
094: */
095: public KnowledgeBase createKB() {
096:
097: KnowledgeBase kb = new AdvancedKnowledgeBase();
098: // Initialize functions and predicates
099:
100: // add rules
101: Rule rule1 = lfs.rule(lfs.prereq(DoubleArithmetic.LESS_THAN,
102: new Double(200.00), lfs.cplx(
103: function_sum_amount_by_customer, lfs
104: .variable("a customer"))), lfs.fact(
105: has_category, lfs.variable("a customer"), "GOLD"));
106: kb.add(rule1);
107: Rule rule2 = lfs.rule(lfs.prereq(has_category, lfs
108: .variable("a customer"), "GOLD"), lfs.fact(
109: gets_discount, lfs.variable("a customer"),
110: new Discount(5.0, true)));
111: kb.add(rule2);
112: Rule rule3 = lfs.rule(lfs.prereq(has_category, lfs
113: .variable("a customer"), "SILVER"), lfs.fact(
114: gets_discount, lfs.variable("a customer"),
115: new Discount(3.0, true)));
116: kb.add(rule3);
117: Rule rule4 = lfs.rule(lfs.prereq(has_category, lfs
118: .variable("a customer"), "STANDARD"), lfs.fact(
119: gets_discount, lfs.variable("a customer"),
120: new Discount(0.0, true)));
121: kb.add(rule4);
122: Rule rule5 = lfs.rule(lfs.prereq(IntArithmetic.LESS_THAN,
123: new Integer(2), lfs.cplx(
124: function_number_transactions_by_customer, lfs
125: .variable("a customer"))), lfs.fact(
126: has_category, lfs.variable("a customer"), "SILVER"));
127: kb.add(rule5);
128: Rule rule6 = lfs.rule(lfs.prereq(DoubleArithmetic.LESS_THAN,
129: new Double(100.0), lfs.cplx(
130: function_max_amount_by_customer, lfs
131: .variable("a customer"))), lfs.fact(
132: has_category, lfs.variable("a customer"), "GOLD"));
133: kb.add(rule6);
134: Fact fact = lfs.fact(has_category, lfs
135: .variable("each customer"), "STANDARD");
136: kb.add(fact);
137:
138: // add queries
139: kb.addQuery(lfs.query(lfs.fact(gets_discount, "Tom", lfs
140: .variable("discount", Discount.class)),
141: "Discount for customer \"Tom\""));
142: kb.addQuery(lfs.query(lfs.fact(gets_discount, "John", lfs
143: .variable("discount", Discount.class)),
144: "Discount for customer \"John\""));
145: kb.addQuery(lfs.query(lfs.fact(gets_discount, "Jim", lfs
146: .variable("discount", Discount.class)),
147: "Discount for customer \"Jim\""));
148: kb.addQuery(lfs.query(lfs.fact(gets_discount, "Ralf", lfs
149: .variable("discount", Discount.class)),
150: "Discount for customer \"Ralf\""));
151: kb.addQuery(lfs.query(lfs.fact(gets_discount, "Bill", lfs
152: .variable("discount", Discount.class)),
153: "Discount for customer \"Bill\""));
154:
155: return kb;
156: }
157:
158: /**
159: * Initialize the functions and predicates.
160: */
161: private void initFunctionsAndPredicates() {
162:
163: // init data source
164: SimpleDataSource dataSource = new SimpleDataSource();
165:
166: // init functions
167: Class[] struct = { String.class };
168:
169: function_max_amount_by_customer = new SQLFunction();
170: function_max_amount_by_customer.setDataSource(dataSource);
171: function_max_amount_by_customer
172: .setQuery(QUERY_MAX_AMOUNT_BY_CUSTOMER);
173: function_max_amount_by_customer
174: .setObjectRelationalMapping(new OneColumnMapping(
175: Double.class));
176: function_max_amount_by_customer
177: .setName("max transaction amount of a customer");
178: function_max_amount_by_customer.setStructure(struct);
179:
180: function_sum_amount_by_customer = new SQLFunction();
181: function_sum_amount_by_customer.setDataSource(dataSource);
182: function_sum_amount_by_customer
183: .setQuery(QUERY_SUM_AMOUNT_BY_CUSTOMER);
184: function_sum_amount_by_customer
185: .setObjectRelationalMapping(new OneColumnMapping(
186: Double.class));
187: function_sum_amount_by_customer
188: .setName("value of all transactions of a customer");
189: function_sum_amount_by_customer.setStructure(struct);
190:
191: function_number_transactions_by_customer = new SQLFunction();
192: function_number_transactions_by_customer
193: .setDataSource(dataSource);
194: function_number_transactions_by_customer
195: .setQuery(QUERY_NUMBER_OF_TRANSACTIONS_BY_CUSTOMER);
196: function_number_transactions_by_customer
197: .setObjectRelationalMapping(new OneColumnMapping(
198: Integer.class));
199: function_number_transactions_by_customer
200: .setName("number of all transactions of a customer");
201: function_number_transactions_by_customer.setStructure(struct);
202:
203: function_last_transaction_date_by_customer = new SQLFunction();
204: function_last_transaction_date_by_customer
205: .setDataSource(dataSource);
206: function_last_transaction_date_by_customer
207: .setQuery(QUERY_DATE_OF_LAST_TRANSACTION_BY_CUSTOMER);
208: function_last_transaction_date_by_customer
209: .setObjectRelationalMapping(new OneColumnMapping(
210: Date.class));
211: function_last_transaction_date_by_customer
212: .setName("date of the last transactions of a customer");
213: function_last_transaction_date_by_customer.setStructure(struct);
214:
215: // predicates
216: Class[] struct2 = { String.class, Discount.class };
217: gets_discount = new SimplePredicate(
218: "a customer gets a discount", struct2);
219:
220: Class[] struct3 = { String.class, String.class };
221: has_category = new SimplePredicate("a customer has a category",
222: struct3);
223:
224: }
225:
226: /**
227: * Save knowledge base to a file "kb.xml".
228: * @param kb a knowledge base
229: */
230: public void saveKB(KnowledgeBase kb) {
231: ZKBManager zkbManager = new ZKBManager();
232: zkbManager.setDriver(new ZKBDriver_1_1());
233: try {
234: //zkbManager.setOps(new XMLSerializationOPS());
235: zkbManager.exportKnowledgeBase(new File("kb.zip"), kb);
236: System.out.println("Knowledge base exported to kb.zip");
237: } catch (ZKBException x) {
238: System.err.println("Cannot export knowledge base");
239: x.printStackTrace();
240: }
241: }
242:
243: }
|