项目要开发一个专家系统,以Jess进行推理决策,以Java作为外层框架进行开发。因为专家系统方向的资料比较少,目前仍然在摸索中。把已经掌握的知识写出了,给个参考。
好在Jess官方提供了一个java+jess的example,虽然没有说明,慢慢摸索理解了一下, 在此与大家分享。
之前的博客中已经给出了Jess作为插件在Eclipse中的安装过程,在此可以直接使用。
一、工程搭建
1、新建一个Dynamic web project;
2、增加jess.jar包,并bulid path;
3、 在该工程中新建一个*.clp文件。(新建文件,手动增加后缀为.clp即可)
如图:
得到的目录如下图:
二、源码分析
下面我们来看项目的源码。
这是一个价格计算的项目,根据消费者购买的商品的数量、价格等进行打折或者提供赠品。
model包中提供了商品目录CatalogItem.java、消费者消费次数Customer.java、消费者订单Order.java及商家提供的优惠活动Offer.java。
demo包中的demo.java是主程序入口,DemoDatabase.java提供数据接口的实现。
diagnosis包中Database.java提供数据接口,PricingEngine.java实现价格计算引擎。正是PricingEngine.java实现了pricing.clp与Java程序连接。
下面是PricingEngine.java中的源码部分。
public class PricingEngine {
private Rete engine;
private WorkingMemoryMarker marker;
private Database database;
public PricingEngine(Database aDatabase) throws JessException {
// Create a Jess rule engine
engine = new Rete();//创建Jess规则引擎
engine.reset();
// Load the pricing rules
engine.batch("pricing.clp");//加载价格规则
// Load the catalog data into working memory
database = aDatabase;
engine.addAll(database.getCatalogItems());//加载目录数据到工作存储区
// Mark end of catalog data for later
marker = engine.mark();//标记目录数据
}
private void loadOrderData(int orderNumber) throws JessException {
// Retrive the order from the database
Order order = database.getOrder(orderNumber);//从数据库获取订单
if (order != null) {
// Add the order and its contents to working memory,增加订单及订单目录到工作存储区
engine.add(order);
engine.add(order.getCustomer());
engine.addAll(order.getItems());
}
}
public Iterator run(int orderNumber) throws JessException {
// Remove any previous order data, leaving only catalog data
engine.resetToMark(marker);//重置规则引擎
// Load data for this order
loadOrderData(orderNumber);//加载数据
// Fire the rules that apply to this order
engine.run();//启动规则引擎
// Return the list of offers created by the rules
return engine.getObjects(new Filter.ByClass(Offer.class));
}
}
将数据库中的内容增加到规则库的存储区中,通过PricingEngine规则引擎来加载规则库
那么,Java如何带动这个规则引擎呢?
下面给出Demo中的main函数,可以看到,通过新建规则库,可以很容易地将规则引擎加入到Java中。
public static void main(String[] args) {
try {
DemoDatabase database = new DemoDatabase();//新建数据库
PricingEngine engine = new PricingEngine(database);//新建规则引擎
processOrder(database, engine, 123);//处理订单
processOrder(database, engine, 567);
processOrder(database, engine, 666);
} catch (JessException e) {
e.printStackTrace();
}
}
那么,将Jess的规则处理加入到了Java中,它是如何处理数据的呢
下面是pricing.clp 中的内容
(import model.*)
(deftemplate Order (declare (from-class Order)))
(deftemplate OrderItem (declare (from-class OrderItem)))
(deftemplate CatalogItem (declare (from-class CatalogItem)))
(deftemplate Customer (declare (from-class Customer)))
(defrule 10%-volume-discount
"Give a 10% discount to everybody who spends more than $100."
?o <- (Order {total > 100})
=>
(add (new Offer "10% volume discount" (/ ?o.total 10))))
可以看到(import model.*)
同Java中的import是一致的。
(declare (from-class Order))这一部分正是从Java的类中获得的。这样Jess就可以使用Java中的对象了。
(defrule 10%-volume-discount
"Give a 10% discount to everybody who spends more than $100."
?o <- (Order {total > 100})
=>
(add (new Offer "10% volume discount" (/ ?o.total 10))))
这一部分的功能是对所有的订单消费超过100$的消费者打九折的优惠。
在Order中的{total}是方法名去掉get,并且将首字母变为小写(如果紧挨着的第二个字母也是大写,则不会变为小写,编写代码时会有智能提示),而不是Java类中的变量名。
程序的运行结果如下