7.查询工作内存(working memory)

7.查询工作内存(working memory)

Jess中的working memory有点类似于数据库;由索引、数据结构组成。大部分情况下,通过规则的模式匹配来访问工作内存。但有时,可以通过编写程序代码直接从工作内存中调用数据。本章将对此作详细描述。

7.1.线性搜索(liner search)

最原始的搜索数据的方法莫过于线性搜索和过滤器(filter),使用一个布尔函数来判断一条数据是否属于被搜索的结果。Jess支持使用这种强行(brute-force)搜索的方式,在工作内存中通过jess.Filter接口,搜索Java对象。在实现jess.Filter接口之后,向jess.Rete.getObjects(jess.Filter)方法传递一个过滤器(filter)的实例(instance),该方法将在被选中的对象上返回一个java.util.Iterator。虽然这一做法在较大的工作内存上并不实用,但确实很便利。下面将运行一个关于Payment对象的Jess程序,然后在工作内存中查询所有Payment对象,并在每个查询结果上调用process()

import jess.*; 
import java.util.Iterator; 
public class ExMyFilter { 
    interface Payment { void process(); } 
    public static void main(String[] argv) throws JessException { 
        Rete engine = new Rete(); 
        engine.batch("cashier.clp"); 
        Iterator it = engine.getObjects(new Filter() { 
            public boolean accept(Object o) { 
                return o instanceof Payment; 
            } 
        }); 
        while (it.hasNext()) { 
            ((Payment) it.next()).process(); 
        } 
    } 
} 

 

 

7.2.定义查询结构(defquery construct)

虽然线性查询很方便,但是其效率不高。定义查询结构(the defquery construct)可以建立一个非右手规则的特殊规则(rule)。一般规则的响应比较自然,而工作内存的查询则直接处于程序的控制下。然而相应的,一条规则对每组匹配的实例相应一次;该查询结构则提供一个jess.QueryResult对象,用以访问所有匹配的查询结果。

使用defquery包括以下三个步骤:

1.       编写查询语句

2.       调用查询

3.       使用查询结果

下面将举例说明。

7.3.个简单的例子

7.3.1.编写查询语句

同上,再编写程序处理一个关于人物信息的数据库。同样使用下列定义模式(deftemplate)

Jess> (deftemplate person (slot firstName) (slot lastName) (slot age)) 

 

假设需要通过查询工作内存找出所有含给定姓氏人物信息。找到该条人物信息后,通过该信息获得其全名及年龄。可以编写查询语句指定欲查询的人物姓氏,从而在匹配名单中找出名字及年龄。

该查询有点类似左手规则。编写一条符合查询需求的模式(pattern)。声明一个名为?ln的变量,成为查询的参数,同时包含变量?fn?age分别表示人物姓氏和年龄。

Jess> (defquery search-by-name 

  "Finds people with a given last name" 

  (declare (variables ?ln)) 

  (person (lastName ?ln) (firstName ?fn) (age ?age))) 

 

下面针对该查询,编写一些具体人物信息作为实例存入工作内存:

Jess> (deffacts data 
  (person (firstName Fred)   (lastName Smith)    (age 12)) 
  (person (firstName Fred)   (lastName Jones)    (age 9)) 
  (person (firstName Bob)    (lastName Thomas)   (age 32)) 
  (person (firstName Bob)    (lastName Smith)    (age 22)) 
  (person (firstName Pete)   (lastName Best)     (age 21)) 
  (person (firstName Pete)   (lastName Smith)    (age 44)) 
  (person (firstName George) (lastName Smithson) (age 1)) 
  ) 
Jess> (reset) 

 

7.3.2.调用查询

定义了一个查询后,可以使用Jess中的run-query*函数调用该查询,或者使用Java中的jess.Rete.runQueryStar(java.lang.String, jess.ValueVector)方法。在上述两种情况下,都必须给定代查询的人物姓氏作为参数代入其中。在Jess中的调用如下:

Jess> (reset) 
Jess> (bind ?result (run-query* search-by-name Smith)) 

 

查询名称及待查询的值分别作为run-query*的参数。函数run-query*返回一个jess.QueryResult对象,该对象存于自定义的名为?result的变量中。

上例在Java中的调用表示如下:

 

Rete engine = ... 
    QueryResult result = engine.runQueryStar("search-by-name", new ValueVector().add("Smith")); 

 

7.3.3.使用查询结果

在本例中仅以打印包含人物全面及年龄的表格为例。

jess.QueryResult的接口类似于java.sql.ResultSet。使用jess.QueryResult.next()调用下一结果,使用getXXX()方法返回该查询中与变量绑定的对应值。下列Jess代码将输出查询结果:

Jess> (while (?result next) 
    (printout t (?result getString fn) " " (?result getString ln) 
                ", age " (?result getInt age) crlf)) 
Fred Smith, age 12 
Bob Smith, age 22 
Pete Smith, age 44 
FALSE 

 

因为工作内存中有三条姓氏同为Smith的人物信息

同样的循环在Java中表示如下:

while (result.next()) { 
    System.out.println(result.getString("fn") + " " + result.getString("ln") 
                       + ", age" + result.getInt("age")); 
} 

 

7.3.4.再次用Java例子进行说明

下面给出完整的Java程序。如上所述,假设“query.clp”已包含于deftemplate,defquerydeffacts

import jess.*; 
public class ExQuery { 
    public static void main(String[] argv) throws JessException { 
        Rete engine = new Rete(); 
        engine.batch("query.clp"); 
        engine.reset(); 
        QueryResult result = 
            engine.runQueryStar("search-by-name", new ValueVector().add("Smith")); 
        while (result.next()) { 
            System.out.println(result.getString("fn") + " " + result.getString("ln") 
                               + ", age" + result.getInt("age")); 
        } 
    } 
} 
C:\> java ExQuery 

 

7.4.变量的声明

在查询中允许出现的两类变量是:1.查询自带(internal)的,如:?age2.在查询外(external)定义的,或者当查询执行时在run-query*命令中指定的,如:?lnJess中默认所有变量都是查询中自带的;必须通过下列语句自行声明外部变量:

(declare (variables ?X ?Y ...)) 

 

这一点类似于强调声明(salience declaration)规则。

7.5.max-background-rules的声明

使用查询触发反向链接很方便。本例中,jess.Rete.run()必须在查询执行中被调用,从而允许反向链接。在此过程中由规则激发的实例将作为查询结果的一部分。(无法理解的读者可以跳过该部分)

默认情况下,一个查询在执行时不能激活规则(fire rule)。如果要在查询时允许反向链接,可以用max-background-rules声明,如下:

(declare (max-background-rules 10)) 

 

由此可运行最多10条规则在这一查询语句执行时被激活。

7.6.count-query-results命令

仅需获取匹配查询条件的结果的数量时,可使用count-query-results函数。该函数所需的参数与run-query*相同,但仅返回等价于匹配个数的一个整数值。

你可能感兴趣的:(数据结构,sql,工作)