4.4.1 演绎信息的检索

4.4.1 演绎信息的检索

为了信息检索,在提供的针对数据库的接口中,逻辑编程的最好。在这章中,
我们实现的查询语言,被设计成使用这种方式。

为了演示查询系统做什么,我们将显示在管理微软的个人记录的数据库中,查询系统是如何被
使用的。微软是在波士顿地区的高技术企业。语言提供了面向模式的读取个人信息。也能利用
做逻辑演绎的通用规则。

* 一个样品数据库

关于微软的个人数据库包括了关于企业个人信息的断言。这个是关于Ben Bitdiddle的个人信息,
一个全职的计算机专家:

(address (Bitdiddle Ben) (Slumerville (Ridge Road) 10))
(job (Bitdiddle Ben) (computer wizard))
(salary (Bitdiddle Ben) 60000)

任何一个断言都是一个列表(在这个案例中是三个),它的元素本身也是列表。

作为一个全职的专家,Ben负责公司的计算机部门,他领导两个程序员和一个技术员。
这里有他们的信息。

(address    (Hacker Alyssa P) (Cambridge (Mass Ave) 78))
(job        (Hacker Alyssa P) (computer programmer))
(salary     (Hacker Alyssa P) 40000)
(supervisor (Hacker Alyssa P) (Bitdiddle Ben))

(address    (Fect Cy D) (Cambridge (Ames Street) 3))
(job        (Fect Cy D) (computer programmer))
(salary     (Fect Cy D) 35000)
(supervisor (Fect Cy D) (Bitdiddle Ben))

(address    (Tweakit Lem E) (Boston (Bay State Road) 22))
(job        (Tweakit Lem E) (computer technician))
(salary     (Tweakit Lem E) 25000)
(supervisor (Tweakit Lem E) (Bitdiddle Ben))

这也有一个程序员实习生。由Alyssa负责指导。

(address    (Reasoner Louis) (Slumerville (Pine Tree Road) 80))
(job        (Reasoner Louis) (computer programmer trainee))
(salary     (Reasoner Louis) 30000)
(supervisor (Reasoner Louis) (Hacker Alyssa P))


所有的这些人都在计算机部门,正如在他们的工作描述中,第一项中的“计算机”
这个词显示的那样。

Ben是一个高级雇员,他的上司是公司的老板本人。
(supervisor  (Bitdiddle Ben) (Warbucks Oliver))
(address    (Warbucks Oliver) (Swellesley (Top Heap Road)))
(job        (Warbucks Oliver) (administration big wheel))
(salary     (Warbucks Oliver) 150000)

除了Ben管理的计算机部门,还有一个会计部门,包括了主会计员和他的助手。

(address    (Scrooge Eben) (Weston (Shady Lane) 10))
(job        (Scrooge Eben) (accounting chief accountant))
(salary     (Scrooge Eben) 75000)
(supervisor (Scrooge Eben) (Warbucks Oliver))

(address    (Cratchet Robert) (Allston (N Harvard Street) 16))
(job        (Cratchet Robert) (accounting scrivener))
(salary     (Cratchet Robert) 18000)
(supervisor (Cratchet Robert) (Scrooge Eben))

这也有一个老板的秘书。

(address    (Aull DeWitt) (Slumerville (Onion Square) 5))
(job        (Aull DeWitt) (administration secretary))
(salary     (Aull DeWitt) 25000)
(supervisor (Aull DeWitt) (Warbucks Oliver))

这个数据库也包括了判断。这个判断是哪一种工作可能由其它的工作岗位来代替。
例如一个计算机专家能做计算机程序员和计算机技术员的工作。

(can-do-job (computer wizard) (computer programmer))
(can-do-job (computer wizard) (computer technician))

一个程序员能做实习生的工作。

(can-do-job (computer programmer) (computer programmer trainee))

也有如下的例子。

(can-do-job (administration secretary)
  (administration big wheel))

* 简单的查询
查询语言允许用户从数据库中检索信息,通过对系统的提示符发出查询语句的响应。
例如,为了扛以所有的计算机程序员,一个可能的说法是:
;;;Query Input:
(job  ?x  (computer  programmer))

系统将返回如下的信息项:

;;;  Query results:
(job  (Hacker Alyssa P)   (computer programmer))
(job  (Fect  Cy  D)   (computer programmer))

输入的查询指定了我们正在找的数据库中的入口,为了匹配一个特定的模式。在这个例子中,
模式指定入口包括三个项,它的第一个项是字面上的符号job,第二个项是任意的内容,
第三个项是字面的列表(computer  programmer).在匹配的列表中的第二个是一个任意的内容,
被指定为一个模式的变量即?x.  一个模式的变量的通用形式是一个符号,以问号开始的,加上变量的名称。
在下面我们将看到为什么为模式变量指定命名而不是仅用一个问号来表示任意内容是很有用的。
对于简单的查询,系统的响应是显示在数据库中匹配特定的模式的所有的入口。

一个模式能有多个变量。例如,如下的查询

(address ?x  ?y)

将列出所有的员工的地址。

一个模式可能没有变量,在这种情况下查询简单地确定模式是否在一个数据库中。如果在,
这有一个匹配,如果不在,这没有匹配。

在一个查询中,同一个模式变量能出现多次,指定相同的任意内容必须在相应的位置上出现。
这也是变量有名称的原因。例如,

(supervisor  ?x  ?x)

找到所有的监督自己的人(尽管在我们的例子数据库中没有这样的人)

查询

(job ?x  (computer ?type))

匹配所有的job,记录的第三个项是一个有两个元素的列表,这个列表的第一项是computer:

(job  (Bitdiddle  Ben)  (computer  wizard))
(job  (Hacker Alyssa P)  (computer  programmer))
(job  (Fect Cy D)  (computer programmer))
(job  (Tweakit Lem E)  (computer technician))

这个模式没有匹配如下的记录:

(job  (Reasoner Louis)  (computer programmer trainee))

因为在这个记录的第三项是一个有三个元素的列表,模式中的第三项指定它有两个元素。
如果我们要修改这个模式,为了第三项以computer开头的任何一个列表,我们能如下的指定:

(job ?x  (computer  . ?type))

例如

(computer  . ?type)

匹配数据(computer programmer trainee) 以?type作为列表 (programmer trainee)
它也匹配数据(computer programmer)以?type作为列表 (programmer )
并且也匹配数据(computer)以?type作为空列表 ( )

我们能描述简单的查询的查询语言过程如下:

系统找到在查询模式中满足模式的对变量的所有的赋值,也就是,对于变量的值的所有的
集合,例如,如果模式变量被值实例化,结果在数据库中。

通过列出满足变量赋值的查询模式的所有的实例,系统返回这个查询。

注意的是,如果模式没有变量,查询归结为对模式是否在数据库中的确定。如果是,空
赋值,没有赋值给变量,对于数据库,满足模式。

练习4.55
为了从数据库中检索如下的信息,给出简单的查询:
a. 被苯监督的所有人
b.在会计部的所有人的姓名和工作
c.  居住在slumerville的所有人的姓名和地址。


* 复合的查询
简单查询形成了查询语言的原生的操作。为了形成复合的操作,
查询语句提供了组合的方法。让查询语句成为一个逻辑编程语言的一个方法是
组合的方法映射为在形成逻辑表达式的组合方法: and,or 和 not.
(这里的and,or 和 not不是lisp的原生程序,而是构建查询语言的操作)

我们能使用and,以如下的方法来找到所有的程序员的地址:

(and  (job  ?person  (computer programmer))
   (address   ?person  ?where))

输出的结果如下:

(and  (job (Hacker Alyssa P)  (computer programmer))
         (address (Hacker Alyssa P) (Cambridge  (Mass Ave)   78)))
(and (job  (Fect Cy  D) (computer  programmer))
        (address  (Fect Cy D)   (Cambridge  (Ames Street)   3)))

总之,

(and <query1>  <query2> ....... <queryn>)

这是同时满足<query1>  <query2> ....... <queryn>所有的条件的值的集合。

正如简单的查询,通过找到满足查询的所有对模式变量的赋值,系统执行了一个复合的查询,
然后,显示了有那些值的查询的实例。

组装复合查询的另一个方法是使用 or。例如

(or  (supervisor   ?x   (Bitdiddle  Ben)) 
       (supervisor   ?x   (Hacker Alyssa  p)))

将找到被苯或者是阿丽莎监督的所有的员工:

(or  (supervisor   (Hacker Alyssa  p)   (Bitdiddle  Ben)) 
       (supervisor   (Hacker Alyssa  p)   (Hacker Alyssa  p)))
(or  (supervisor   (Fect Cy D)   (Bitdiddle  Ben)) 
       (supervisor   (Fect Cy D)   (Hacker Alyssa  p)))
(or  (supervisor   (Tweakit  Lem E)   (Bitdiddle  Ben)) 
       (supervisor   (Tweakit  Lem E)   (Hacker Alyssa  p)))
(or  (supervisor   (Reasoner Louis)   (Bitdiddle  Ben)) 
       (supervisor   (Reasoner Louis)   (Hacker Alyssa  p)))

总之,

(or <query1>  <query2> ....... <queryn>)

这是至少满足<query1>  <query2> ....... <queryn>的条件之一的值的集合。

组装复合查询的另一个方法是使用 not。例如

(and  (supervisor   ?x  (Bitdiddle Ben)) 
         (not  (job ?x   (computer programmer))))

找出被苯监督却不是程序员的员工:总之,

(not <query1>)

这是找到不满足条件<query1>的集合。

最后一个组合的形式是被叫做lisp-value.当lisp-value是一个模式的第一个元素时,它指定
下一个元素是一个Lisp的判断式,被应用其它的元素,都是它的参数。总之,

(lisp-value  <predicate>   <arg1>  ...  <argn>)

如果<predicate>  被应用到 <arg1>  ...  <argn>是真的时,条件被满足。例如,为了找到
工资大于30000美元的所有的人,我们能有如下的写法:

(and  (salary   ?person   ?amount) 
         (lisp-value   >  ?amount    30000))

练习4.56
写出检索如下的信息的复合查询:

a.  被苯监督的所有的人的姓名和地址
b.  工资小于苯的所有的人,结合他们的工资和苯的工资
c.  被不在计算机部门的人监督的所有的人,包括监督人的姓名和工作。

*规则
除了原生的查询和复合的查询,查询语言提供了抽象查询的方法。这叫做规则。规则如下:

(rule  (lives-near   ?person1  ?person2)  
         (and  (address   ?person1  (?town .   ?rest1))
                  (address   ?person2  (?town .   ?rest2))
                  (not (same  ?person1 ?person2))))

上面的规则指定了如果两个人居住在同一个镇,这两个人彼此居住的很近。
最后的Not子句排除了所有的人与自己居住的近的规则。相同的关系被一个
很简单的规则定义:

(rule  (same  ?x  ?x))

如下的规则声明了一个人在组织中是一个间接的领导。如果他监督了某人,
而这个人也成了监督者:

(rule  (wheel  ?person)
        (and  (supervisor  ?middle-manager  ?person) 
                 (supervisor  ?x   ?middle-manager)))

一个规则的通用形式是

(rule  <conclusion>  <body>)

<conclusion> 是一个模式, <body>任意的查询。我们能认为一个规则表示
一个大的甚至是无限的判断式的集合,命名了规则结论的所有的实例,并且变量
的赋值满足查询的语句。当我们描述简单的查询,如果实例化的模式在数据库中,
我们说对变量的赋值满足了一个模式。但是模式不需要显式地在数据库中作为一个判断式。
它能成为一个被规则应用的隐式的判断式。例如,查询

(lives-near  ?x  (Bitdiddle  Ben))

结果如下:

(lives-near  (Reasoner Louis)  (Bitdiddle  Ben))
(lives-near  (Aull DeWitt)   (Bitdiddle  Ben))

为了找到居住在苯附近的所有的程序员,我们能写如下的查询:

(and  (job  ?x  (computer  programmer))  
         (lives-near   ?x  (Bitdiddle  Ben)))

作为复合的程序的例子,规则能被使用作为其它的规则的一部分,
(正如在上面的lives-near我们看到的那样)或者甚至被递归地定义。
例如,下面的规则

(rule  (outranked-by  ?staff-person   ?boss) 
         (or  (supervisor   ?staff-person  ?boss) 
                (and  (supervisor   ?staff-person  ?middle-manager) 
                         (outranked-by   ?middle-manager  ?boss))))

说法是如果老板是这个人的监督者,或者是递归地说一个人的监督者比老板的级别低,
那么一个员工比一个组织中的老板级别低。

练习4.57
定义一个规则,第一个人能代替第二个人。如果第一个人能做第二个人的工作,
或者是某人能做第一个人的工作也能做第二个人的工作,并且如果第一个人和第二个人不是一个人。
使用你的规则,给出查询,找到如下的信息:

a.  能代替Cy的所有的人
b. 能代替某人,且工资更低的所有的人,并且结合两者的工资。

练习4.58
定义一个规则,来指定一个人在部门中是大亨。如果这个人工作在部门中,在部门中
却没有监督他的人。

练习4.59
苯总是错过会议。让他害怕的是,忘记会议的习惯可能让他失去工作,苯决定做一些事。
他添加了所有的周会议到数据库中,通过如下的内容:

(meeting  accounting  (Monday  9am))
(meeting   administration  (Monday 10am))
(meeting computer  (Wednesday  3pm))
(meeting  administration  (Friday  1pm))

如上的内容的每一个是部门中的一个会议。苯也添加了一个公司级
的会议的入口,来描述所有的部门。公司的所有的员工都参加这个会议。

(meeting  whole-company  (Wednesday  4pm))

a.  在周五的早上,苯想要查询数据库,来找到发生在这一天的所有的会议。
  他应该使用什么查询?
b. 阿丽莎是不满意的。她认为能够通过指定她的姓名来查询她要参加的会议
才更有用。 所以,她设计了一个规则,一个人的会议包括所有的公司级会议,
加上她所在的部门的会议。填写阿丽莎的规则的程序部分。

(rule  (meeting-time   ?person  ?day-and-time)
   <rule-body>)

c. 阿丽莎在周三早晨到了公司,查询这天她必须参加的会议。已经有了如上的规则,
为了完成任务,她要做什么查询?

练习4.60
通过如下的查询

(lives-near  ?person  (Hacker Alyssa  P))

阿丽莎能找到谁居住在她的附近,她能和谁一起去工作。在另一方面,
当她要找到居住在附近的人对,通过查询

(lives-near  ?person1 ?person2)

她注意到居住在附近的任何一对人,都被列出了两次,例如,

(lives-near  (Hacker  Alyssa P)  (Fect Cy  D))
(lives-near    (Fect Cy  D)  (Hacker  Alyssa P))

为什么发生了这种情况?有一种方式,找到居住在她附近的人的列表吗?
任何一对人,只显示一次吗?解释一下。

*逻辑作为程序
我们能认为一个规则是一个类型的逻辑含义:如果对模式变量的赋值满足条件,
那么,它满足条件的结论。因此, 我们能认为查询语言有能力基于规则执行逻辑推导。
作为一个例子,考虑一下在4.4部分中的开头处的描述的append操作。正如我们所说的,
append能使用如下的两个规则来描述它的特征:

 对于任何列表y,空列表与y  append形成 y
 对于任何的u,v,y,z,如果v,y append形成z,
那么 (cons  u  v)和 y  append 形成 (cons  u  z)

在我们的查询语言中,为了表达这个内容,我们为如下的关系定义了两个规则,

(append-to-form  x  y  z)

我们能解释 x,y append 形成 z 的含义

(rule  (append-to-form  ()  ?y  ?y))
(rule  (append-to-form  (?u   .   ?v)    ?y  (?u  .  ?z))
     (append-to-form  ?v ?y  ?z))

第一条规则没有程序体,它意味着结论支持?y的任何内容。
注意的是第二条规则使用了点符号,来命名一个列表的car,cdr.

根据这两条规则 ,我们能够写出计算两个列表的添加的查询来。

;;;Query Input:
(append-to-form  (a b)  (c d) ?z)
;;;;  Query results;
(append-to-form  (a b)  (c d)   (a b c d))

更灵活的是什么,我们能使用相同的规则问问题“哪个列表与列表
(a b)结合,生成列表(a  b c d)” 做法如下:

;;;Query Input:
(append-to-form  (a b)  ?y   (a  b  c d))
;;;;  Query results;
(append-to-form  (a b)  (c d)   (a b c d))

我们也能问有哪些列表的数对 结合生成了(a b c d):

;;;Query Input:
(append-to-form  ?x  ?y   (a  b  c d))
;;;;  Query results;
(append-to-form  ()  (a b c d)   (a b c d))
(append-to-form  (a)  (b c d)   (a b c d))
(append-to-form  (a b)  (c d)   (a b c d))
(append-to-form  (a b c)  (d)   (a b c d))
(append-to-form  (a b c d)  ()   (a b c d))

在为了上述的查询推导答案时,在使用规则时,查询系统可能似乎显出一些智能来。
实际上,正如我们将在下一部分中看到的那样,系统在使用一种非常确定的算法,
来阐述规则。不幸的是,尽管系统在append的例子上,工作得很得利,在更复杂的例子中,
通用的方法可能失效了,这正如我们在4.4.3部分中看到的。

练习4.61
如下的规则实现了一个关系next-to,它要找到一个列表中的相邻的元素:

(rule  (?x  next-to  ?y  in (?x ?y  .  ?u)))
(rule   (?x  next-to  ?y  in (?v  .  ?z)) 
          (?x  next-to  ?y  in ?z))

如下的查询返回的结果是什么?

(?x  next  to ?  in (1  (2 3)  4))
(?x  next  to  1  in  (2 1 3 1))

练习4.62
定义一个规则,实现练习2.17中的last-pair操作,它返回的是一个非空的列表中
的包含最后一个元素的列表。在查询(last-pair  (3)  ?x), (last-pair  (1 2 3)  ?x),
(last-pair  (2  ?x)  (3)),上检查你的规则。你的规则能正常地工作在查询上吗?例如
(last-pair  ?x   (3)) ?

练习4.63
根据家谱,如下的数据库跟踪了Ada的祖行的谱系,直到Adam。

(son  Adam  Cain)
(son  Cain  Enoch)
(son  Enoch  Irad)
(son  Irad Mehujael)
(son  Mehujael  Methushael)
(son Methushael Lamech)
(wife  Lamech Ada)
(son Ada  Jabal)
(son Ada  Jubal)

写出规则 例如“S是F的儿子,并且F是G的儿子,那么S是G的孙子”
“如果W是M的妻子,并且S是W的儿子,那么S是M的儿子”
(可以认为在古代时比现在的规则更多)将让查询系统找到Gain的孙子,
Lamech的儿子,Methushael的孙子(为了推导更复杂的关系,
见练习4.69中的规则)

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/82980193