1. 程式人生 > >4.4.1 演繹資訊的檢索

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中的規則)