—— 2006 年 7 月 18 日,沈崴於廣州
一、高性能智能數據庫定義
智能數據庫,一如其名,能夠對數據庫中的數據進行智能管理。常規數據庫中的很多要素,在智能數據庫中都是系統自動處理的,而非必須。比如關係數據庫中的表及列結構,對象數據庫中的路徑等。
智 能數據庫只提供兩個接口,set 和 get。set 接口提供了對數據的新增和編輯的接口。get 是查詢接口,我們可以想象成 sql 或者搜索引擎的查詢接口,或者直接使用自然語言來和查詢機器人對話。在這種情況下,我們只需要往數據庫裏面塞數據對象,而無需爲之定義一個特定的表結構或者類 (Class)。系統自動負責存儲策略。
高性能智能數據庫,乃是提升智能數據庫的效率和性能。目前對於結構重復的大量數據,關係數據庫能夠得到較好的性能; 對於數型結構的數據,對象數據庫有較好的性能。高性能智能數據庫就是對數據存儲自動適配策略,使之永遠接近最佳策略。對於結構複雜的大量數據接近關係數據庫,對於邏輯數據接近對象數據庫的性能。而這一切都無需人的參與,都由系統來進行。
智能數據庫,是數據庫程序員的最終理想,能夠絕滅數據庫編程,將編程轉換為配置 (不用編程的框架,是框架生産力的極致)。換而言之程序員將讓位於管理員,約束該放什麽、該看什麽。而高性能是此類數據庫能夠實用的基礎。
二、高性能智能數據庫要素
1) 各種存儲模型和存儲介質。因爲既然高性能智能數據能夠將數據適配到最佳介質上,那麽我們手頭上就必須掌握這些存儲模型和介質。
2) 數據到存儲的適配算法。算法判斷數據的數據結構類型,決定其存儲方式。
3) 外置索引。因爲既然要跨介質查詢,那麽索引必須是外置的。
4) 自然語言查詢引擎。對一大堆隻知道索引不知道類型的數據,能夠想像最好的查詢方法是自然語言。
三、高性能智能數據庫介質實現
1、數據庫類型
關於存儲介質,在設計初,我們可以使用 MysqL、sqlite、Beckley DB 一類的二維數據庫用於存放重復的簡單數據,一旦一批數據被認爲非常相似,他們將被存放在一起,確切地說,一個表中。
文 件系統負責放置大型文檔對象,通常是一個對象的屬性節點。這時,文件系統的目錄被用來抽象大型對象,對象輕量級的屬性被串行化為該目錄下一個類似於 XML 的文件中。當情況繼續複雜下去,這個對象所屬的子對象示情況,用子目錄和 sqlite 或者 Beckley DB 來存儲。通常用 sqlite 這樣的文件數據庫來抽象巨量數據可以和文件系統抽象的邏輯很好地結合在一起,而 MysqL 這種連接型數據庫就相當困難了,所以在智能數據庫中 sqlite 和 Beckley DB 是首選。當需要做分佈式連接時,可以面向文件數據庫、文件系統和其他存儲介質一起做成一個分佈式服務接口 (統一 DBMS 接口)。最後,我們需要越過 iNode (資源限制) 對文件系統的摧殘,這是文件系統介質需要認真考慮的一個問題。
對付帶有邏輯結構的數據,對象數據庫 (可能還有 IBM 大型機上那種層次模型數據庫) 是個好主意。ZODB 當仁不讓。同樣 ZODB 是文件型數據庫,可以和上述兩種介質很好地集成。
(注意,本節中所提及的 XML 是不可用的串行化協議,僅做比喻之用。而在對象數據庫中幾乎不可能用到 XML 串行化協議,除非你在和一批弱智的原教旨主義者一起工作 -- 這很不幸)
2、串行化,相似度、相關性及特性合並 (BAT 數據模型)
當數據類型信息成爲非必須的因素,數據結構就成爲不確定的東西。至少在目前,我們手上的存儲介質都無法存儲非確定結構的東西。在關係數據庫中,表結構是需要確定的。而 ZODB 的傳統用法中,類也是必須的,事實上這在很大程度上是索引輸出的需要。
數據要存儲到那些介質中去,則必須進行串行化以減少特徵數量,將特徵數減少到一個特定數量。確定數量的特性字段便可以存儲到確定結構的表結構和類型中去了。
使用串行化來合併對象特性,需要掌握一定的原則。記住,其中需要合併的是,相似的、相關性大的特性字段 (具體方法請見下面第六章,以及第七章的第 4 節,所謂的 BAT 數據模型)。
當這些工作完成之後,計算機自動聚類便可以開始,其中,對不同的串行化結果字段,面向文本進行聚類或許能夠得到意想不到的效果。
四、外部索引
特 性字段的合併,並不意味著這些字段成了一個,也不意味這些字段的索引也合併了。我們仍然可以取得 (合併前) 單個原始字段的内容,同時可以對單個原始字段進行索引和搜索。事實上,我們目前仍然沒有適合的外部索引來支持這項功能。和存儲介質一樣,我們需要合併索引字段。因爲是通過相似度和相關性的原則來進行索引合併,因此可以降低一部分副作用,但是信息缺失無法避免 (對字段的索引變成對字段們的索引)。可以使用將需要獨立索引的屬性對象化 (通常子對象擁有獨立索引),或者使用其它方法來避免信息卻失,但是這會降低系統性能,這是我們需要權衡的。
Xapwrap 和 Jakarta Lucene 都是非常好用並且成熟的外部索引工具,並且都有 Python 接口。在 ZODB 中可以使用 ZCatalog 和 IndexedCatalog。
五、自然語言查詢引擎
嚴格地說外部索引以及智能數據庫自動聚類算法,都應該算是自然語言查詢體系中的重要組成部分。而自然語言解析,我們這裡狹義的自然語言查詢引擎,僅是查詢引擎表現層而已。
目 前在表現層最爲適合的,是 AIML 這樣的工具。Prolog 或許也算一個。只要外部索引完成 AIML 或者 Prolog 的導出,自然語言查詢便水到渠成。然而 AIML 資料的信息緊密度不夠,過於依賴内存也是個問題。結合 ZODB 也許是一個選擇。爲此你必須在 AIML 的基礎上重新設計一套更合適的協議,但是請不要使用 Yacc/Lex,因爲你將面對一個未知數量級的源碼數量 (也就是索引),我們需要的是一個編譯器的無棧實現 (经过我的实践,发现这并没有想象中那么困难)。
六、基礎算法
也 許實現智能數據庫並不需要複雜的算法,但是要高性能地實現,算法就是必須的。算法,是高性能的核心。聚類算法是比較重要的,一個好的聚類函數,能夠提升命中率,將接近的數據整合在一起,可能是一個關係表中,也可能是一個 XML、JSON 或者 Python Pickle 文件中,也可能是 BTree、文件系統的文件夾、Hash Table 中。具體存儲位置視該類型數據的重復度、複雜度和數據大小決定的。完成聚類之後,決定介質就是小兒科了。目前在數據挖掘領域,聚類算法已經是相當成熟了,我們所要做的,僅僅是挑一种合適速度的算法出來而已。
情況 變化後,需要將數據在各個介質和存儲位置之間轉移,調整。比如突然發現數據已經從低重復度變爲高重復度,可能就需要將這些數據從 XML/Pickle/HashTable 中轉移到關係數據庫或者 ZODB 中去以提高速度。什麽時候檢查、什麽時候調整,是個學問。這種調整算法,更爲貼切的説法是一種 "策略"。
字段合併算法,涉及到相似性與相關性,和確定特性數量的權衡。基本上,這些算法是沒有道理的,就如用於解釋這個世界的哲學一樣多。不過我們可能會因禍得福,經驗算法可能成爲最爲有效的算法。比如將對象屬性簡單按取值域分爲三類,Boolean、Attribute 以及 Text (簡稱 BAT),並按照這個標準將對象所有的屬性合併,能夠得到三個特定的字段。通常,根據經驗 Boolean 和 Attribute 特性的原始字段之間的相似性和相關性是相當大的,將他們串行化、合併成一個字段共同存取,損失的效率相對要小,或者幾乎無損。合併算法,可能就這麽簡單。
七、常見問題
1) 智能數據庫是否需要對像的路徑和類型信息?
ZODB 具有對象得路徑和類型信息,MysqL 的表結構也是一种類型信息並且隱喻了路徑的存在。我們似乎有理由相信,類型和路徑信息是必須存在的。否則如何架設應用? 不錯,這個觀點是正確的,在人工智能查詢工具出現之前,沒有類型和路徑我們確實無法準確定義數據的位置,無法修改和刪除。但是,一旦人工智能成熟,我們可以像問路一樣找到數據,這時數據類型和路徑信息就開始顯得多於。而數據的類型最終將由其抽象數據結構特徵決定,數據路徑由機械聚類算法決定。這時數據庫結構和工作原理變得於人類大腦非常接近,不過是一個記性牢靠的大腦 (人腦儲存機制僅僅是增加了遺忘功能,這是人腦的一大優點,請參見拙作《自然语言环境(中文)下的人工智能理论及实践》)。而在智能數據庫研究初期,我們必須容忍類型和路徑的存在,用於定位我們的數據,但是我們必須提供脫離他們的機制。
2) 海量存儲?
智 能數據庫對付海量存儲,至少在目前仍然是乏力的。我們可以使用分佈式的方法來解決容量和性能的問題,然而外置索引也是異乎尋常龐大的東西,似乎只有 Google 這種專業的公司能做出漂亮的方案。不過很明顯,外置索引也必須是分佈式的。智能數據庫的出現的一個重要目的就是來跨應用,以方便數據挖掘的應用。所以海量數據是智能數據最後必須面對的難題,分佈式,是最後需要考慮的問題。
3) 智能數據庫爲什麽能絕滅數據庫編程?
不 僅僅是數據庫編程,甚至應用編程都已經不需要。面向智能數據庫,我們將使用智能客戶端,智能客戶端能夠根據數據的抽象類型,或者元類型 (Metadata) 自動組織顯示和數據的增刪改,元類型工作組件甚至能夠自動判斷提交時機而不需要用戶擊發提交按鈕,並且自動刷新。在智能數據庫下,智能客戶端的實現變得非常容易,它不需要關心存儲邏輯,因爲數據存在哪裏已經有數據庫在關心了。而數據視野、權限以及業務邏輯 (這裡指有限狀態工作流,這種工作流可以很方便地用管理工具來配置) 都是管理員所需要關心的。
4) 爲什麽對象的所有屬性可以串行化成 Boolean、Attribute 和 Text 三種呢 (BAT 數據模型)? 這樣劃分有何意義?
根 據取值域的大小來區別屬性,有一個最簡單的好處。就是小型數據的靈活性往往較高,大型數據的靈活性往往較低; 同時小型 (屬性) 數據之間的關聯度往往較高,大型屬性數據之間的關聯度較低。將不同取值域的數據區別開來,讓他們的存取協同起來,往往能得到類似於 "預讀命中" 的效果。而使用其它標準,將關聯度較低的數據、靈活度不同的數據串行化合併在一起,明顯要顯得愚蠢得多。
那麽爲什麽是 Boolean、Attribute 和 Text 這三種取值域呢? 嗯,非常簡單,我們目前常見的基礎編輯組件無非是 Radio、CheckBox、Line、Textarea 這麽幾種。Radio 的取值域為 Boolean,CheckBox 和 Line 的取值域相同,是 Attribute。最後一种 Textarea 則歸為 Text。事實上根據我(沈崴) 在 1997 年提出的數學背景論 (我爲了計算 24 點而設計的一種數學理論,參見《24 點研究》),發現利用 Boolean、Attribute 及 Text 取值域來逆向推導整數緯運算,發現在 Text 取值域,取值已經幾乎是不收斂的,換而言之,在我們這個空間中,不存在實際可用的第四種取值域和字段類型 (宇宙學應用除外)。抛開數學模型,這也是一種有現實意義的經驗模型。
然後我們就可以設計一種簡單的串行化協議來展開畫外之音。假設有這麽一個被串行化的對象:
Object "Foo"
Boolean "B1:yes;B2:no;B3:yes"
Attribute "A1:value1;A2:value2;A3:value3"
Text "TEXT1:... content1 ...;TEXT2:... content2 ..."
_1、其中,可以對 Boolean 進行縮寫,減去取值為假的字段,只留下真値的字段名,成爲 Boolean "B1;B2"。這裡信息其實並沒有缺失,查詢時如果無法得到 "B2" 字段名,證明 "B2" 在 "Foo" 中為假。
_2、Attribute 字段無法壓縮。
_3、Text 字段因爲取值龐大,因此互相之間的相關性和靈活性是非常低的,因此可以考慮互相獨立為數據節點,以提高存取效率。
最後串行化結果如下:
Object "Foo"
Boolean "B1;B2"
Attribute "A1:value1;A2:value2;A3:value3"
TextNode "TEXT1"
"... content1 ..."
TextNode "TEXT2"
"... content2 ..."
這 時我們可以發現 "Boolean" 數據的實際含義是 "對象實際具有的特性",比如說 "人類;男性;小孩"。"Attribute" 用於 "短" 屬性,比如 "年齡:20;籍貫:浙江;人品:極好"。Text 字段用於備註、照片等。其字段間的相關程度一目了然,並且涵蓋了大部分的應用場景,這三種字段也分別對應 KeywordIndex、FieldIndex、TextIndex 三種索引類型。整個聚類體系是建立在這種分類算法的基礎上的。
5) 高性能智能數據庫已經出現了嗎?
高性能智能數據庫還遠未到實現的時候。我們能做的,就是不斷地接近、接近、接近。事實上,這項工作應該交給科研機構來實現,比如大學。哦,當然不是國内的大學! 等待國外相關理論和技術的成熟看來是個好主意。