由于工作需要,筆者在HP UX, Soralis 上面設置了Oracle Intermedia來實現(xiàn)全文檢索。目前已經(jīng)投入實際使用。設置過程中有許多問題和經(jīng)驗,拿來和大家交流。本文依據(jù)的是Oracle 8.1.6 和8.1.7兩個版本,不能保證適用于其他版本。
目前全文檢索功能幾乎所有主流數(shù)據(jù)庫都支持。此前筆者曾在sql server 2000上實現(xiàn),感覺非常簡單,方便,但創(chuàng)建全文檢索索引的時間比較長,通常要十幾個小時。Oracle 的全文檢索建立和維護索引都要快得多,筆者的65萬記錄的一個表建立索引只需要20分鐘,同步一次只需要1分鐘。但設置就要復雜得多。
一.設置過程
1.首先,檢查你的數(shù)據(jù)庫是否安裝了intermedia
這可以通過檢查是否有ctxsys用戶和ctxapp角色(role). 如果沒有這個用戶和角色,意味著你的數(shù)據(jù)庫創(chuàng)建時未安裝intermedia功能。你必須修改數(shù)據(jù)庫以安裝這項功能。
修改過程:
運行 $ORACLE_HOME/bin/dbassist, 選擇'modify database', 然后在選擇數(shù)據(jù)庫功能時將j server 和 intermedia 都選上(安裝intermedia必須同時安裝jserver).強烈建議你在做這個改動前先備份整個數(shù)據(jù)庫。
2.設置extproc
Oracle 是通過所謂的"外部調(diào)用功能"(external procedure)來實現(xiàn)intermedia的,因此正確地設置extproc是關(guān)鍵一步。
首先要配置listener 使它能監(jiān)聽intermedia 調(diào)用的請求。你可以通過運行$ORACLE_HOME/bin/netassit 來進行配置,也可以手工修改配置文件:$ORACLE_HOME/admin/listener.ora ,然后重新啟動listener。下面以一個例子來講述如何手工修改配置文件。
打開listener.ora文件,在修改前,通常有如下內(nèi)容(假定使用缺省listener):
LISTENER =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYDATABASE)(PORT = 1521))
)
SID_LIST_LISTENER =
(SID_DESC =
(GLOBAL_DBNAME = mydatabase.world)
(ORACLE_HOME = /u01/app/oracle/product/8.1.6)
(SID_NAME = mydatabase)
)
這個listener還沒有配置extproc, 因此,需要為它增加對extproc的監(jiān)聽,辦法就是分別增加description 和 sid_desc. 修改后的listner.ora 如下:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = MYDATABASE)(PORT = 1521))
)
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = mydatabase.world)
(ORACLE_HOME = /u01/app/oracle/product/8.1.6)
(SID_NAME = mydatabase)
)
(SID_DESC =
(PROGRAM = extproc)
(SID_NAME = PLSExtProc)
(ORACLE_HOME = /u01/app/oracle/product/8.1.6)
)
)
注意上面的host, global_dbname,sid_name,oracle_home應填寫你的數(shù)據(jù)庫的實際值,但program一項必須填寫extproc.
其次,要配置服務器端的tnsnames.ora文件。該文件的位置在$ORACLE_HOME/admin下面。同樣可以通過運行netasst來進行配置。
在tnsnames.ora文件中需要增加如下一項:
EXTPROC_CONNECTION_DATA,EXTPROC_CONNECTION_DATA.WORLD =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
)
(CONNECT_DATA =
(SID = PLSExtProc)
)
)
注意其中,KEY 和SID必須與listener.ora中的key 和sid_name對應相同。
修改完成后,重新啟動listener (先用lsnrctl stop, 然后 lsnrctl start), 然后,使用tnsping 來測試一下是否配置正確:
tnsping extproc_connection_data 或者
tnsping extproc_connection_data.world,如果配置正確,會顯示:
Attempting to contact (ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC)) OK(140毫秒)
否則請檢查你的上述兩個文件,并注意,在修改后一定要重新啟動listener,但并不需要重新啟動數(shù)據(jù)庫。
3.設置詞法分析器(lexer)
Oracle實現(xiàn)全文檢索,其機制其實很簡單。即通過Oracle專利的詞法分析器(lexer),將文章中所有的表意單元(Oracle 稱為 term) 找出來,記錄在一組 以 dr$開頭的表中,同時記下該term出現(xiàn)的位置、次數(shù)、hash 值等信息。檢索時,Oracle 從這組表中查找相應的 term,并計算其出現(xiàn)頻率,根據(jù)某個算法來計算每個文檔的得分(score),即所謂的"匹配率"。而lexer則是該機制的核心,它決定了全文檢索的效率。Oracle 針對不同的語言提供了不同的 lexer, 而我們通常能用到其中的三個:
basic_lexer: 針對英語。它能根據(jù)空格和標點來將英語單詞從句子中分離,還能自動將一些出現(xiàn)頻率過高已經(jīng)失去檢索意義的單詞作為"垃圾"處理,如if , is 等,具有較高的處理效率。但該lexer應用于漢語則有很多問題,由于它只認空格和標點,而漢語的一句話中通常不會有空格,因此,它會把整句話作為一個term,事實上失去檢索能力。以"中國人民站起來了"這句話為例,basic_lexer 分析的結(jié)果只有一個term ,就是"中國人民站起來了"。此時若檢索"中國",將檢索不到內(nèi)容。
chinese_vgram_lexer: 專門的漢語分析器,支持所有漢字字符集。該分析器按字為單元來分析漢語句子。"中國人民站起來了"這句話,會被它分析成如下幾個term: "中","中國","國人","人民","民站","站起",起來","來了","了"?梢钥闯,這種分析方法,實現(xiàn)算法很簡單,并且能實現(xiàn)"一網(wǎng)打盡",但效率則是差強人意。
chinese_lexer: 這是一個新的漢語分析器,只支持utf8字符集。上面已經(jīng)看到,chinese vgram lexer這個分析器由于不認識常用的漢語詞匯,因此分析的單元非常機械,像上面的"民站","站起"在漢語中根本不會單獨出現(xiàn),因此這種term是沒有意義的,反而影響效率。chinese_lexer的最大改進就是該分析器 能認識大部分常用漢語詞匯,因此能更有效率地分析句子,像以上兩個愚蠢的單元將不會再出現(xiàn),極大 提高了效率。但是它只支持 utf8, 如果你的數(shù)據(jù)庫是zhs16gbk字符集,則只能使用笨笨的那個Chinese vgram lexer.
如果不做任何設置,Oracle 缺省使用basic_lexer這個分析器。要指定使用哪一個lexer, 可以這樣操作:
第一.在ctxsys用戶下建立一個preference:
begin ctx_ddl.create_preference('my_lexer','chinese_vgram_lexer'); end;
第二.在建立intermedia索引時,指明所用的lexer:
create index myindex on mytable(mycolumn) indextype is ctxsys.context parameters('lexer my_lexer');
這樣建立的全文檢索索引,就會使用chinese_vgram_lexer作為分析器。
4.使用job定時同步和優(yōu)化
在intermedia索引建好后,如果表中的數(shù)據(jù)發(fā)生變化,比如增加或修改了記錄,怎么辦?由于對表所發(fā)生的任何dml語句,都不會自動修改索引,因此,必須定時同步(sync)和優(yōu)化(optimize)索引,以正確反映數(shù)據(jù)的變化。
在索引建好后,我們可以在該用戶下查到Oracle自動產(chǎn)生了以下幾個表:(假設索引名為myindex):
DR$myindex$I,DR$myindex$K,DR$myindex$R,DR$myindex$N
其中以I表最重要,可以查詢一下該表,看看有什么內(nèi)容:
select token_text, token_count from DR$I_RSK1$I where rownum<=20;
這里就不列出查詢接過了。可以看到,該表中保存的其實就是Oracle 分析你的文檔后,生成的term記錄在這里,包括term出現(xiàn)的位置、次數(shù)、hash值等。當文檔的內(nèi)容改變后,可以想見這個I表的內(nèi)容也應該相應改變,才能保證Oracle在做全文檢索時正確檢索到內(nèi)容(因為所謂全文檢索,其實核心就是查詢這個表)。那么如何維護該表的內(nèi)容呢?總不能每次數(shù)據(jù)改變都重新建立索引吧!這就用到sync 和 optimize了。
同步(sync):將新的term 保存到I表;
優(yōu)化(optimize):清除I表的垃圾,主要是將已經(jīng)被刪除的term從I表刪除。
Oracle提供了一個所謂的ctx server來做這個同步和優(yōu)化的工作,只需要在后臺運行這個進程,它會監(jiān)視數(shù)據(jù)的變化,及時進行同步。但筆者使用ctxserver碰到了許
關(guān)鍵詞標簽:Oracle,UNIX,服務器