Oracle全文檢索方面的研究(全)

參考百度文檔:

http://wenku.baidu.com/view/c53e9e36a32d7375a417801a.html

 

1、準備流程        

 

1.1檢查和設置數據庫角色

首先檢查數據庫中是否有CTXSYS用戶和CTXAPP腳色。如果沒有這個用戶和角色,意味着你的數據庫創建時未安裝intermedia功能。你必須修改數據庫以安裝這項功能。 默認安裝情況下,ctxsys用戶是被鎖定的,因此要先啓用ctxsys的用戶。

默認ctxsys用戶是被鎖定的且密碼即時失效,所以我們以sys用戶進入em,然後修改ctxsys用戶的狀態和密碼。如圖:

 

1.2 賦權 

                測試用戶以之前已經建好的foo用戶爲例,以該用戶下的T_DOCNEWS爲例

先以sys用戶dba身份登錄,對foo賦resource,connect權限

GRANT resource, connect  to foo;

 

再以ctxsys用戶登錄並對foo用戶賦權

GRANT  ctxapp  TO foo;

GRANT execute ON ctxsys. ctx_cls  TO foo;

GRANT execute ON ctxsys. ctx_ddl  TO foo;

GRANT execute ON ctxsys. ctx_doc  TO foo;

GRANT execute ON ctxsys. ctx_output TO foo;

GRANT execute ON ctxsys. ctx_query TO foo;

GRANT execute ON ctxsys. ctx_report  TO foo;

GRANT execute ON ctxsys. ctx_thes  TO foo;

GRANT execute ON ctxsys. ctx_ulexer TO foo;

 

查看系統默認的oracle text 參數

Select pre_name, pre_object from ctx_preferences

 

 

2、Oracle Text 索引原理

Oracle text 索引將文本中所有的字符轉化成記號(token),如www.taobao.com 會轉化

成www,taobao,com 這樣的記號。

Oracle10g 裏面支持四種類型的索引,context,ctxcat,ctxrule,ctxxpath

 

 

2.1 Context 索引

Oracle text 索引把全部的word 轉化成記號,context 索引的架構是反向索引(inverted

index),每個記號都映射着包含它自己的文本位置,如單詞dog 可能會有如下的條目

這表示dog 在文檔doc1,doc3,doc5 中都出現過。索引建好之後,系統中會自動產生

如下DR$MYINDEX$I,DR$MYINDEX$K,DR$MYINDEX$R,DR$MYINDEX$X,MYTABLE5 個表(假設表爲

mytable, 索引爲myindx) 。Dml 操作後, context 索引不會自動同步, 需要利用

ctx_ddl.sync_index 手工同步索引。

 

例子:

Create table docs (id number primary key, text varchar2(200));

Insert into docs values(1, '<html>california is a state in the us.</html>');

Insert into docs values(2, '<html>paris is a city in france.</html>');

Insert into docs values(3, '<html>france is in europe.</html>');

Commit;

/

--建立context 索引

Create index idx_docs on docs(text)

indextype is ctxsys.context parameters

('filter ctxsys.null_filter section group ctxsys.html_section_group');

--查詢

Column text format a40;     --字符串截爲40位顯示。

Select id, text from docs where contains(text, 'france') > 0;

 

id text

---------- -------------------------------

3 <html>france is in europe.</html>

2 <html>paris is a city in france.</html>

--繼續插入數據

Insert into docs values(4, '<html>los angeles is a city in california.</html>');

Insert into docs values(5, '<html>mexico city is big.</html>');

commit;

Select id, text from docs where contains(text, 'city') > 0;--新插入的數據沒有查詢到

 

id text

--------------------------------------------

2 <html>paris is a city in france.</html>

 

 

--索引同步

begin

ctx_ddl.sync_index('idx_docs', '2m');  --使用2M同步索引

end;

--查詢

Column text format a50;

Select id, text from docs where contains(text, 'city') > 0; --查到數據

id text

-----------------------------------------------

5 <html>mexico city is big.</html>

4 <html>los angeles is a city in california.</html>

2 <html>paris is a city in france.</html>

 

 

-- or 操作符

Select id, text from docs where contains(text, 'city or state ') > 0;

--and 操作符

Select id, text from docs where contains(text, 'city and state ') > 0;

或是

Select id, text from docs where contains(text, 'city state ') > 0;

 

--score 表示得分,分值越高,表示查到的數據越精確

SELECT SCORE(1), id, text FROM docs WHERE CONTAINS(text, 'oracle', 1) > 0;

Context 類型的索引不會自動同步,這需要在進行Dml 後,需要手工同步索引。與context 索引相對於的查詢操作符爲contains

 

2.2 Ctxcat 索引

用在多列混合查詢中

Ctxcat 可以利用index set 建立一個索引集,把一些經常與ctxcat 查詢組合使用的查詢列添加到索引集中。比如你在查詢一個商品名時,還需要查詢生產日期,價格,描述等,你可可以將這些列添加到索引集中。oracle 將這些查詢封裝到catsearch 操作中,從而提高全文索引的效率。在一些實時性要求較高的交易上,context 的索引不能自動同步顯然是個問題,ctxcat則會自動同步索引

 

 

例子:

Create table auction(Item_id number,Title varchar2(100),Category_id number,Price number,Bid_close date);

Insert into auction values(1, 'nikon camera', 1, 400, '24-oct-2002');

Insert into auction values(2, 'olympus camera', 1, 300, '25-oct-2002');

Insert into auction values(3, 'pentax camera', 1, 200, '26-oct-2002');

Insert into auction values(4, 'canon camera', 1, 250, '27-oct-2002');

Commit;

 

 

/

--確定你的查詢條件(很重要)

--Determine that all queries search the title column for item descriptions

--建立索引集

begin

ctx_ddl.create_index_set('auction_iset');

ctx_ddl.add_index('auction_iset','price'); /* sub-index a*/

end;

--建立索引

Create index auction_titlex on auction(title) indextype is ctxsys.ctxcat

parameters ('index set auction_iset');

Column title format a40;

Select title, price from auction where catsearch(title, 'camera', 'order by price')> 0;

 

 

Title price

--------------- ----------

Pentax camera 200

Canon camera 250

Olympus camera 300

Nikon camera 400

 

 

Insert into auction values(5, 'aigo camera', 1, 10, '27-oct-2002');

Insert into auction values(6, 'len camera', 1, 23, '27-oct-2002');

commit;

 

 

 

/

--測試索引是否自動同步

Select title, price from auction where catsearch(title, 'camera',

'price <= 100')>0;

 

Title price

--------------- ----------

aigo camera 10

len camera 23

 

 

添加多個子查詢到索引集:

 

begin

ctx_ddl.drop_index_set('auction_iset');

ctx_ddl.create_index_set('auction_iset');

ctx_ddl.add_index('auction_iset','price'); /* sub-index A */

ctx_ddl.add_index('auction_iset','price, bid_close'); /* sub-index B */

end;

 

drop index auction_titlex;

 

Create index auction_titlex on auction(title) indextype is ctxsys.ctxcat

parameters ('index set auction_iset');

SELECT * FROM auction WHERE CATSEARCH(title, 'camera','price = 200 order by bid_close')>0;

SELECT * FROM auction WHERE CATSEARCH(title, 'camera','order by price, bid_close')>0;

 

任何的Dml 操作後,Ctxcat 的索引會自動進行同步,不需要手工去執行,與ctxcat 索引相對應的查詢操作符是catsearch.

語法:

Catsearch(

[schema.]column,

Text_query varchar2,

Structured_query varchar2,

Return number;

例子:

catsearch(text, 'dog', 'foo > 15')

catsearch(text, 'dog', 'bar = ''SMITH''')

catsearch(text, 'dog', 'foo between 1 and 15')

catsearch(text, 'dog', 'foo = 1 and abc = 123')

 

2.3 Ctxrule 索引

The function of a classification application is to perform some action based on document content.

These actions can include assigning a category id to a document or sending the document to a user.

The result is classification of a document.

 

 

例子:

Create table queries (query_id number,query_string varchar2(80));

insert into queries values (1, 'oracle');

insert into queries values (2, 'larry or ellison');

insert into queries values (3, 'oracle and text');

insert into queries values (4, 'market share');

commit;

 

Create index queryx on queries(query_string) indextype is ctxsys.ctxrule;

Column query_string format a35;

Select query_id,query_string from queries

where matches(query_string,

'oracle announced that its market share in databases

increased over the last year.')>0;

query_id query_string

---------- -----------------------------------

1 oracle

4 market share

 

 

在一句話中建立索引匹配查詢

 

2.4 Ctxxpath 索引

Create this index when you need to speed up existsNode() queries on an XMLType column

 

 

 

3. 索引的內部處理流程

 

3.1 Datastore 屬性

數據檢索負責將數據從數據存儲(例如 web 頁面、數據庫大型對象或本地文件系統)

中取出,然後作爲數據流傳送到下一個階段。Datastore 包含的類型有Direct datastore,

Multi_column_datastore, Detail_datastore, File_datastore, Url_datastore, User_datastore,

Nested_datastore。

 

 

 

 

 

 

3.1.1.Direct datastore

支持存儲數據庫中的數據,單列查詢.沒有attributes 屬性

支持類型:char, varchar, varchar2, blob, clob, bfile,or xmltype.

例子:

Create table mytable(id number primary key, docs clob);

Insert into mytable values(111555,'this text will be indexed');

Insert into mytable values(111556,'this is a direct_datastore example');

Commit;

--建立 direct datastore

Create index myindex on mytable(docs)

indextype is ctxsys.context

parameters ('datastore ctxsys.default_datastore');

Select * from mytable where contains(docs, 'text') > 0;

 

3.1.2.Multi_column_datastore

適用於索引數據分佈在多個列中

the column list is limited to 500 bytes

支持number 和date 類型,在索引之前會先轉化成textt

raw and blob columns are directly concatenated as binary data.

不支持long, long raw, nchar, and nclob, nested table

 

Create table mytable1(id number primary key, doc1 varchar2(400),doc2 clob,doc3

clob);

 

Insert into mytable1 values(1,'this text will be indexed','following example creates amulti-column ','denotes that the bar column ');

Insert into mytable1 values(2,'this is a direct_datastore example','use this datastore when your text is stored in more than one column','the system concatenates the text columns');

Commit;

 

/

--建立 multi datastore 類型

Begin

Ctx_ddl.create_preference('my_multi', 'multi_column_datastore');

Ctx_ddl.set_attribute('my_multi', 'columns', 'doc1, doc2, doc3');

End;

--建立索引

Create index idx_mytable on mytable1(doc1)indextype is ctxsys.context

parameters('datastore my_multi')

Select * from mytable1 where contains(doc1,'direct datastore')>0;

Select * from mytable1 where contains(doc1,'example creates')>0;

注意:檢索時,檢索詞對英文,必須是有意義的詞,比如,

Select * from mytable1 where contains(doc1,' more than one column ')>0;

可以查出第二條紀錄,但你檢索more將沒有顯示,因爲more在那句話中不是有意義的一個詞。

 

--只更新從表,看是否能查到更新的信息

Update mytable1 set doc2='adladlhadad this datastore when your text is stored test' where

id=2;

Begin

Ctx_ddl.sync_index('idx_mytable');

End;

Select * from mytable1 where contains(doc1,'adladlhadad')>0; --沒有記錄

Update mytable1 set doc1='this is a direct_datastore example' where id=2; --更新主表

 

Begin

Ctx_ddl.sync_index('idx_mytable');--同步索引

End;

Select * from mytable1 where contains(doc1,'adladlhadad')>0; -查到從表的更新

對於多列的全文索引可以建立在任意一列上,但是,在查詢時指定的列必須與索引時指定的

列保持一致,只有索引指定的列發生修改,oracle 纔會認爲被索引數據發生了變化,僅修改

其他列而沒有修改索引列,即使同步索引也不會將修改同步到索引中.

也就是說,只有更新了索引列,同步索引才能生效,,要更改其他列的同時也要再寫一次即可。

在多列中,對任意一列建立索引即可,更新其他列的同時,在update那個列,同步索引一次即可看到效果了。

 

 

 

3.1.3 Detail_datastore

適用於主從表查詢(原文:use the detail_datastore type for text stored directly in the database in

detail tables, with the indexed text column located in the master table)

因爲真正被索引的是從表上的列,選擇主表的那個列作爲索引並不重要,但是選定之後,查

詢條件中就必須指明這個列

主表中的被索引列的內容並沒有包含在索引中

DETAIL_DATASTORE 屬性定義

 

 

 

 

 

例子:

create table my_master –建立主表

(article_id number primary key,author varchar2(30),title varchar2(50),body varchar2(1));

create table my_detail –建立從表

(article_id number, seq number, text varchar2(4000),

constraint fr_id foreign key (ARTICLE_ID) references my_master (ARTICLE_ID));

--模擬數據

insert into my_master values(1,'Tom','expert on and on',1);

insert into my_master values(2,'Tom','Expert Oracle Database Architecture',2);

commit;

insert into my_detail values(1,1,'Oracle will find the undo information for this transaction

either in the cached

undo segment blocks (most likely) or on disk ');

insert into my_detail values(1,2,'if they have been flushed (more likely for very large

transactions).');

insert into my_detail values(1,3,'LGWR is writing to a different device, then there is no

contention for

redo logs');

insert into my_detail values(2,1,'Many other databases treat the log files as');

insert into my_detail values(2,2,'For those systems, the act of rolling back can be

disastrous');

commit;

--建立 detail datastore

begin

ctx_ddl.create_preference('my_detail_pref', 'DETAIL_DATASTORE');

ctx_ddl.set_attribute('my_detail_pref', 'binary', 'true');

ctx_ddl.set_attribute('my_detail_pref', 'detail_table', 'my_detail');

ctx_ddl.set_attribute('my_detail_pref', 'detail_key', 'article_id');

ctx_ddl.set_attribute('my_detail_pref', 'detail_lineno', 'seq');

ctx_ddl.set_attribute('my_detail_pref', 'detail_text', 'text');

end;

--創建索引

CREATE INDEX myindex123 on my_master(body) indextype is ctxsys.context

parameters('datastore my_detail_pref');

select * from my_master where contains(body,'databases')>0

--只更新從表信息,看是否還能查到

update my_detail set text='undo is generated as a result of the DELETE, blocks are modified,

and redo is sent over to

the redo log buffer' where article_id=2 and seq=1

begin

ctx_ddl.sync_index('myindex123','2m'); --同步索引

end;

select * from my_master where contains(body,'result of the DELETE')>0 –沒有查到剛纔的更新

--跟新從表後,更新主表信息

update my_master set body=3 where body=2

begin

ctx_ddl.sync_index('myindex123','2m');

end;

select * from my_master where contains(body,'result of the DELETE')>0 –查到數據

如果更新了子表中的索引列,必須要去更新主表索引列來使oracle 認識到被索引數據發生變

化(這個可以通過觸發器來實現)。

 

 

 

 

3.1.4 File_datastore

適用於檢索本地服務器上的文件(原文:The FILE_DATASTORE type is used for text stored in

files accessed through the local file system.)

多個路徑標識:Unix 下冒號分隔開如path1:path2:pathn Windows 下用分號;分隔開

create table mytable3(id number primary key, docs varchar2(2000));

 

insert into mytable3 values(111555,'1.txt');

 

insert into mytable3 values(111556,'1.doc');

 

commit;

 

--建立 file datastore

begin

ctx_ddl.create_preference('COMMON_DIR2','FILE_DATASTORE');

ctx_ddl.set_attribute('COMMON_DIR2','PATH','D:\search');

end;

--建立索引

create index myindex3 on mytable3(docs) indextype is ctxsys.context parameters ('datastore COMMON_DIR2');

select * from mytable3 where contains(docs,'word')>0; --查詢

 

--暫時測試支持doc,txt

 

 

3.1.5 Url_datastore

適用於檢索internet 上的信息,數據庫中只需要存儲相應的url 就可以

 

例子:

create table urls(id number primary key, docs varchar2(2000));

insert into urls values(111555,'http://context.us.oracle.com');

insert into urls values(111556,'http://www.sun.com');

insert into urls values(111557,'http://www.itpub.net');

insert into urls values(111558,'http://www.ixdba.com');

commit;

/

--建立url datastore

begin

ctx_ddl.create_preference('URL_PREF','URL_DATASTORE');

ctx_ddl.set_attribute('URL_PREF','Timeout','300');

end;

--建立索引

create index datastores_text on urls (docs) indextype is ctxsys.context parameters

( 'Datastore URL_PREF' );

select * from urls where contains(docs,'Aix')>0

若相關的url 不存在,oracle 並不會報錯,只是查詢的時候找不到數據而已。

oracle 中僅僅保存被索引文檔的url 地址,如果文檔本身發生了變化,必須要通過修改索引

列(url 地址列)的方式來告知oracle,被索引數據已經發生了變化。

 

 

 

3.1.6.User_datastore

Use the USER_DATASTORE type to define stored procedures that synthesize documents during

indexing. For example, a user procedure might synthesize author, date, and text columns into one

document to have the author and date information be part of the indexed text.

 

 

3.1.7 Nested_datastore

全文索引支持將數據存儲在嵌套表中

 

 

 

3.1.8.參考腳本

--建立direct_store

Create index myindex on mytable(docs)

indextype is ctxsys.context

parameters ('datastore ctxsys.default_datastore');

--建立mutil_column_datastore

Begin

Ctx_ddl.create_preference('my_multi', 'multi_column_datastore');

Ctx_ddl.set_attribute('my_multi', 'columns', 'doc1, doc2, doc3');

End;

Create index idx_mytable on mytable1(doc1)indextype is ctxsys.context

parameters('datastore my_multi')

--建立file_datafilestore

begin

ctx_ddl.create_preference('COMMON_DIR','FILE_DATASTORE');

ctx_ddl.set_attribute('COMMON_DIR','PATH','/opt/tmp');

end;

create index myindex on mytable1(docs) indextype is ctxsys.context parameters ('datastore

COMMON_DIR');

--建立url_datastore

begin

ctx_ddl.create_preference('URL_PREF','URL_DATASTORE');

ctx_ddl.set_attribute('URL_PREF','Timeout','300');

end;

create index datastores_text on urls (docs) indextype is ctxsys.context parameters

( 'Datastore URL_PREF' );

 

 

3.2 Filter 屬性

過濾器負責將各種文件格式的數據轉換爲純文本格式,索引管道中的其他組件只能處理純文本數據,不能識別 microsoft word 或 excel 等文件格式,filter 有charset_filter、

inso_filter、null_filter、user_filter、procedure_filter 幾種類型。(可將文檔格式轉化爲數據庫文本格式等。)

 

 

 

 

3.2.1 CHARSET_FILTER

把文檔從非數據庫字符轉化成數據庫字符(原文:Use the CHARSET_FILTER to convert

documents from a non-database character set to the character set used by the database)

 

例子:

create table hdocs ( id number primary key, fmt varchar2(10), cset varchar2(20),

text varchar2(80)

);

begin

cxt_ddl.create.preference('cs_filter', 'CHARSET_FILTER');

ctx_ddl.set_attribute('cs_filter', 'charset', 'UTF8');

end

insert into hdocs values(1, 'text', 'WE8ISO8859P1', '/docs/iso.txt');

insert into hdocs values (2, 'text', 'UTF8', '/docs/utf8.txt');

commit;

create index hdocsx on hdocs(text) indextype is ctxsys.context

parameters ('datastore ctxsys.file_datastore

filter cs_filter

format column fmt

charset column cset');

 

 

 

3.2.2 NULL_FILTER

默認屬性,不進行任何過濾

oracle 不建議對html、xml 和plain text 使用auto_filter 參數,oracle 建議你使用

null_filter 和section group type

--建立null filter

create index myindex on docs(htmlfile) indextype is ctxsys.context

parameters('filter ctxsys.null_filter section group ctxsys.html_section_group');

Filter 的默認值會受到索引字段類型和datastore 的類型的影響,對於存儲在數據庫中的

varchar2、char 和clob 字段中的數據,oracle 自動選擇了null_filtel,若datastore 的屬性設置爲

file_datastore,oracle 會選擇 auto_filter 作爲默認值。

 

3.2.3 AUTO_FILTER

通用的過濾器,適用於大部分文檔,包括PDF 和Ms word,過濾器還會自動識別出plain-text, HTML, XHTML,

SGML 和XML 文檔

Create table my_filter (id number, docs varchar2(1000));

Insert into my_filter values (1, 'Expert Oracle Database Architecture.pdf');

Insert into my_filter values (2, '1.txt');

Insert into my_filter values (3, '2.doc');

commit;

/

--建立 file datastore

Begin

ctx_ddl.create_preference('test_filter', 'file_datastore');

ctx_ddl.set_attribute('test_filter', 'path', '/opt/tmp');

End;

--錯誤信息表

select * from CTX_USER_INDEX_ERRORS

--建立 auto filter

Create index idx_m_filter on my_filter (docs) indextype is ctxsys.context

parameters ('datastore test_filter filter ctxsys.auto_filter');

select * from my_filter where contains(docs,'oracle')>0

 

AUTO_FILTER 能自動識別出大部分格式的文檔,我們也可以顯示的通過column 來指定文檔類型,有text,binary,ignore,設置爲binary 的文檔使用auto_filter,設置爲text 的文檔使用null_filter,設置爲ignore的文檔不進行索引。

create table hdocs (id number primary key,fmt varchar2(10),text varchar2(80));

insert into hdocs values(1, 'binary', '/docs/myword.doc');

insert in hdocs values (2, 'text', '/docs/index.html');

insert in hdocs values (2, 'ignore', '/docs/1.txt');

commit;

create index hdocsx on hdocs(text) indextype is ctxsys.context

parameters ('datastore ctxsys.file_datastore filter ctxsys.auto_filter format column

fmt');

 

3.2.4 MAIL_FILTER

通過mail_filter 把RFC-822,RFC-2045 信息轉化成索引文本

限制:

文檔必須是us-ascii

長度不能超過1024bytes

document must be syntactically valid with regard to RFC-822

 

 

3.2.5 USER_FILTER

Use the USER_FILTER type to specify an external filter for filtering documents in a column

 

3.2.6 PROCEDURE_FILTER

Use the PROCEDURE_FILTER type to filter your documents with a stored procedure. The stored procedure is called

each time a document needs to be filtered.

 

3.2.7 參考腳本

--建立null filter

create index myindex on docs(htmlfile) indextype is ctxsys.context

parameters('filter ctxsys.null_filter section group ctxsys.html_section_group');

--建立 auto filter

Create index idx_m_filter on my_filter (docs) indextype is ctxsys.context

parameters ('datastore test_filter filter ctxsys.auto_filter');

 

Filter 錯誤記錄表:CTX_USER_INDEX_ERRORS

 

 

3.3 Lexer 屬性

                Oracle 全文檢索的lexer 屬性用於處理各種不同的語言,最基本的英文使用basic_lexer,

中文則可以使用chinese_vgram_lexer 或chinese_lexer。

 

 

 

 

 

 

 

3.3.1 Basic_lexer

basic_lexer 屬性支持如英語、德語、荷蘭語、挪威語、瑞典語等以空格作爲界限的語言(原

文:Use the BASIC_LEXER type to identify tokens for creating Text indexes for English and all

other supported whitespace-delimited languages.)

Create table my_lex (id number, docs varchar2(1000));

Insert into my_lex values (1, 'this is a example for the basic_lexer');

Insert into my_lex values (2, 'he following example sets Printjoin characters ');

Insert into my_lex values (3, 'To create the INDEX with no_theme indexing and with printjoins characters');

Insert into my_lex values (4, '中華人民共和國');

Insert into my_lex values (5, '中國淘寶軟件');

Insert into my_lex values (6, '測試basic_lexer 是否支持中文');

Commit;

 

/

--建立basic_lexer

begin

ctx_ddl.create_preference('mylex', 'BASIC_LEXER');

ctx_ddl.set_attribute ('mylex', 'printjoins', '_-'); --保留_ -符號

ctx_ddl.set_attribute ( 'mylex', 'index_themes', 'NO');

ctx_ddl.set_attribute ( 'mylex', 'index_text', 'YES');

ctx_ddl.set_attribute ('mylex','mixed_case','yes'); --區分大小寫

end;

create index indx_m_lex on my_lex(docs) indextype is ctxsys.context parameters('lexer

mylex');

Select id from my_lex where contains(docs, 'no_theme') > 0;

select docs from my_lex where contains(docs,'中國')>0

 

3.3.2 Mutil_lexer

支持多種語言的文檔,比如你可以利用這個lexer 來定義包含Endlish,German 和Japanese 的

文檔(原文:Use MULTI_LEXER to index text columns that contain documents of different

languages. For example, you can use this lexer to index a text column that stores English, German,

and Japanese documents.)建立一個multi_lexer 屬性的索引,並通過language 列設置需要索

引的語言,Oracle 會根據language 列的內容去匹配add_sub_lexer 過程中指定的語言標識符,如果匹配的上,就使用該sub_lexer 作爲索引的lexer,如果沒有找到匹配的,就使用default語言作爲索引的lexer 列,注意客戶端nls_language,可能會影響lexer 的選擇

 

Select * from v$nls_parameters where parameter = 'NLS_LANGUAGE';

alter session set nls_language='simplified chinese';

alter session set nls_language='american';

 

 

例子:

create table globaldoc ( doc_id number primary key,lang varchar2(3),text clob);

--建立multi_lexer

begin

ctx_ddl.create_preference('english_lexer','basic_lexer');

ctx_ddl.set_attribute('english_lexer','index_themes','yes');

ctx_ddl.set_attribute('english_lexer','theme_language','english');

ctx_ddl.create_preference('german_lexer','basic_lexer');

ctx_ddl.set_attribute('german_lexer','composite','german');

ctx_ddl.set_attribute('german_lexer','mixed_case','yes');

ctx_ddl.set_attribute('german_lexer','alternate_spelling','german');

ctx_ddl.create_preference('japanese_lexer','japanese_vgram_lexer');

ctx_ddl.create_preference('global_lexer', 'multi_lexer');

ctx_ddl.add_sub_lexer('global_lexer','default','english_lexer');

ctx_ddl.add_sub_lexer('global_lexer','german','german_lexer','ger');

ctx_ddl.add_sub_lexer('global_lexer','japanese','japanese_lexer','jpn');

end;

create index globalx on globaldoc(text) indextype is ctxsys.context

parameters ('lexer global_lexer language column lang');

 

 

 

3.3.3 chinese_vgram_lexer 和chinese_lexer

basic_lexer 只能識別出被空格、標點和回車符分隔出來的部分,如果要對中文內容進行索引的話,就必須使用chinese_vgram_lexer 或是chinese_lexer

Chinese_lexer 相比chinese_vgram_lexer 有如下的優點:

產生的索引更小

更好的查詢響應時間

產生更接近真實的索引切詞,使得查詢精度更高

支持停用詞

因爲chinese_lexer 採用不同的算法來標記tokens, 建立索引的時間要比chinese_vgram_lexer

長.

字符集:支持al32utf8,zhs16cgb231280,zhs16gbk,zhs32gb18030,zht32euc,zht16big5

zht32tris, zht16mswin950,zht16hkscs,utf8

--建立chinese lexer

Begin

ctx_ddl.create_preference('my_chinese_vgram_lexer', 'chinese_vgram_lexer');

ctx_ddl.create_preference('my_chinese_lexer', 'chinese_lexer');

End;

-- chinese_vgram_lexer

Create index ind_m_lex1 on my_lex(docs) indextype is ctxsys.context Parameters ('lexer foo.my_chinese_vgram_lexer');

Select * from my_lex t where contains(docs, '中國') > 0;

-- chinese_lexer

drop   index ind_m_lex1 force; 

Create index ind_m_lex2 on my_lex(docs) indextype is ctxsys.context

Parameters ('lexer ctxsys.my_chinese_lexer');

Select * from my_lex t where contains(docs, '中國') > 0;

3.3.4 User_lexer

Use USER_LEXER to plug in your own language-specific lexing solution. This enables you to

define lexers for languages that are not supported by Oracle Text. It also enables you to define a

new lexer for a language that is supported but whose lexer is inappropriate for your application.

 

3.3.5 Default_lexer

如果數據庫在建立的時候指定的是中文則default_lexer 爲chinese_vgram_lexer,如果是英文,則default_lexer 爲basic_lexer

 

3.3.6 Query_procedure

This callback stored procedure is called by Oracle Text as needed to tokenize words in the query.

A space-delimited group of characters (excluding the query operators) in the query will be

identified by Oracle Text as a word.

 

3.3.7 參考腳本

--建立basic_lexer

begin

ctx_ddl.create_preference('mylex', 'BASIC_LEXER');

ctx_ddl.set_attribute ('mylex', 'printjoins', '_-'); --保留_ -符號

ctx_ddl.set_attribute ('mylex','mixed_case','yes'); --區分大小寫

end;

create index indx_m_lex on my_lex(docs) indextype is ctxsys.context parameters('lexer

mylex');

--建立 chinese_vgram_lexer 或是chinese_lexer

Begin

ctx_ddl.create_preference('my_chinese_vgram_lexer', 'chinese_vgram_lexer');

ctx_ddl.create_preference('my_chinese_lexer', 'chinese_lexer');

End;

-- chinese_vgram_lexer

Create index ind_m_lex1 on my_lex(docs) indextype is ctxsys.context

Parameters ('lexer ctxsys.my_chinese_vgram_lexer');

 

 

3.4 Section Group 屬性

Section group 支持查詢包含內部結構的文檔(如html、xml 文檔等),可以指定對文檔

的某一部分進行查詢,你可以將查詢範圍限定在標題head 中。在html、xml 等類似結構的文

檔中,除了用來顯示的內容外,還包括了大量用於控制結構的標識,而這些標識可能是不希望被索引的,這就是section group 的一個主要功能(原文:In order to issue WITHIN queries on document sections, you must create a section group before you define your sections)

3.4.1 Null_section_group

系統默認,不進行任何節的過濾

例子:

Create table my_sec (id number, docs varchar2(100));

Insert into my_sec values (1, 'a simple section group, test null_section_group attribute.');

Insert into my_sec values (2, 'this record one, can be query in nornal');

Insert into my_sec values (4, 'this record

are tested for

the query in paragraph');

Commit;

/

--定義null_section_group

Create index ind_m_sec on my_sec(docs) indextype is ctxsys.context

parameters ('section group ctxsys.null_section_group');

Select * from my_sec where contains(docs, 'record and query') > 0;

--要預先定義sentence 或paragraph',否則查詢會出錯

Select * from my_sec where contains(docs, '(record and query) within sentence') > 0;

Begin

ctx_ddl.create_section_group('test_null', 'null_section_group');

ctx_ddl.add_special_section('test_null', 'sentence');

ctx_ddl.add_special_section('test_null', 'paragraph');

End;

drop index ind_m_sec;

Create index ind_m_sec on my_sec(docs) indextype is ctxsys.context

parameters ('section group test_null');

Select * from my_sec where contains(docs, '(record and query) within sentence') > 0;

Select * from my_sec where contains(docs, '(record and query) within paragraph') > 0;

 

3.4.2 Basic_section_group

basic_section_group 纔是支持節搜索的最基礎的一種屬性,但是它只支持以<tag>開頭以

</tag>結尾的結構的文檔

Create table my_sec1 (id number, docs varchar2(1000));

Insert into my_sec1 values (1, '<heading>title</heading>

<context>this is the contents of the example.

Use this example to test the basic_section_group.</context>');

Insert into my_sec1 values (2, '<heading>example</heading>

<context>this line incluing the word title too.</context>');

Commit;

/

Create index ind_my_sec1 on my_sec1(docs) indextype is ctxsys.context;

Select * from my_sec1 where contains (docs, 'heading') > 0;

--定義basic_section_group

Begin

Ctx_ddl.create_section_group('test_basic', 'basic_section_group');

End;

drop index ind_my_sec1;

Create index ind_my_sec1 on my_sec1(docs) indextype is ctxsys.context

parameters ('section group test_basic');

Select * from my_sec1 where contains (docs, 'heading') > 0;

Select * from my_sec1 where contains (docs, 'context') > 0;

Select * from my_sec1 where contains (docs, 'use') > 0;

節搜索的另一個主要功能就是可以限制查詢的範圍,上面的文檔包含了兩部分,標題和正文,

其中標題使用標籤<heading>,正文使用標籤<context>,我們可以對basic_section_group 添加

區域屬性,運行查詢在文檔的某個範圍內進行

Drop index ind_my_sec1;

Begin

ctx_ddl.add_zone_section('test_basic', 'head', 'heading');

End;

Create index ind_my_sec1 on my_sec1(docs) indextype is ctxsys.context

parameters ('section group test_basic');

Select * from my_sec1 where contains (docs, 'title') > 0;

--在head 裏面查詢

Select * from my_sec1 where contains (docs, 'title within head') > 0;

 

3.4.3 Html_section_group

Html 文檔具有很多不規範的表示方法,oracle 建議使用html_section_group 以便能夠得到更

好的識別

--定義html_section_group

begin

ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');

end;

create index myindex on docs(htmlfile) indextype is ctxsys.context

parameters('filter ctxsys.null_filter section group htmgroup');

無論是field_section 還是zone_section,表示文檔的tag 標籤都是大小寫敏感的,其大小寫需

要和原文中匹配

 

3.4.4.Xml_section_group

Xml 文檔的格式要求比html 文檔嚴謹、規範, 這也使得xml_section_group 比

html_section_group 具有了更多的功能

例子:

Create table my_sec2 (id number, docs varchar2(1000));

Insert into my_sec2 values (1, 'context.xml');

commit;

/

--定義xml_section_group

Begin

ctx_ddl.create_preference('test_file', 'file_datastore');

ctx_ddl.set_attribute('test_file', 'path', '/opt/tmp');

ctx_ddl.create_section_group('test_html', 'html_section_group');

ctx_ddl.create_section_group('test_xml', 'xml_section_group');

End;

Create index ind_t_docs on my_sec2 (docs) indextype is ctxsys.context

parameters('datastore ctxsys.test_file filter ctxsys.null_filter section group

ctxsys.test_xml')

Begin

ctx_ddl.add_attr_section('test_xml', 'name', 'const@name');

End;

Select * from my_sec2 where contains (docs, 'complete within name') > 0;

 

3.4.5.Auto_section_group

Xml_section_group 的增強型,對於xml_section_group 用戶需要自己添加需要定義的節組,

而使用auto_section_group,則oracle 會自動添加節組以及屬性信息

 

3.4.6 Path_section_group

和auto_section_group 十分類似,path_section_group 比auto_section_group 增加了haspath 和

inpath 操作,但是path_section_group 不支持add_stop_section 屬性

 

3.4.7 參考腳本

--建立null_section_group

Create index ind_m_sec on my_sec(docs) indextype is ctxsys.context

parameters ('section group ctxsys.null_section_group');

--建立basic_section_group

Begin

Ctx_ddl.create_section_group('test_basic', 'basic_section_group');

End;

Begin

ctx_ddl.add_zone_section('test_basic', 'head', 'heading'); --設定節查詢

End;

Create index ind_my_sec1 on my_sec1(docs) indextype is ctxsys.context

parameters ('section group test_basic');

--建立Html_section_group

begin

ctx_ddl.create_section_group('htmgroup', 'HTML_SECTION_GROUP');

end;

create index myindex on docs(htmlfile) indextype is ctxsys.context

parameters('filter ctxsys.null_filter section group htmgroup');

--建立Xml_section_group

Begin

ctx_ddl.create_section_group('test_xml', 'xml_section_group');

End;

Create index ind_t_docs on my_sec2 (docs) indextype is ctxsys.context

parameters('filter ctxsys.null_filter section group ctxsys.test_xml')

 

 

3.5 Storage 屬性

Oracle 全文檢索通常會生成一系列的輔助表,生成規則是dr$+索引名+$+表用途標識,

由於這些表是oracle 自動生成的,通常沒有辦法爲這些表指定存儲空間。爲構造text 索引所

生成的輔助表指定表空間、存儲參數(use the storage preference to specify tablespace and

creation parameters for tables associated with a text index),oracle 提供了單一的存儲類型

basic_storage。  

在mytable1 表中建立了全文索檢索myindex,系統中會自動產生如下5 個表:

DR$MYINDEX$I,DR$MYINDEX$K,DR$MYINDEX$R,DR$MYINDEX$X,MYTABLE1

 

 

參考腳本

--建立basic storage

Begin

Ctx_ddl.create_preference('mystore', 'basic_storage'); --建立storage

Ctx_ddl.set_attribute('mystore', --設置參數

'i_table_clause',

'tablespace foo storage (initial 1k)');

Ctx_ddl.set_attribute('mystore',

'k_table_clause',

'tablespace foo storage (initial 1k)');

Ctx_ddl.set_attribute('mystore',

'r_table_clause',

'tablespace users storage (initial 1k) lob

 

(data) store as (disable storage in row cache)');

Ctx_ddl.set_attribute('mystore',

'n_table_clause',

'tablespace foo storage (initial 1k)');

Ctx_ddl.set_attribute('mystore',

'i_index_clause',

'tablespace foo storage (initial 1k) compress 2');

Ctx_ddl.set_attribute('mystore',

'p_table_clause',

'tablespace foo storage (initial 1k)');

End;

--建立索引

Create index indx_m_word on my_word(docs) indextype is ctxsys.context

parameters('storage mystore');

 

 

 

3.6 Wordlist 屬性

Oracle 全文檢索的wordlist 屬性用來設置模糊查詢和同詞根查詢,wordlist 屬性還支持

子查詢和前綴查詢,oracle 的wordlist 屬性只有basic_wordlist 一種(原文:Use the wordlist

preference to enable the query options such as stemming, fuzzy matching for your language. You

can also use the wordlist preference to enable substring and prefix indexing, which improves

performance for wildcard queries with CONTAINS and CATSEARCH.)

3.6.1 例子:

Create table my_word (id number, docs varchar2(1000));

Insert into my_word values (1, 'Specify the stemmer used for word stemming in Text queries');

Insert into my_word values (2, 'Specify which fuzzy matching routines are used for the

column');

Insert into my_word values (3, 'Fuzzy matching is currently supported for English');

Insert into my_word values (4, 'Specify a default lower limit of fuzzy score. Specify a

number between 0 and 80');

Insert into my_word values (5, 'Specify TRUE for Oracle Text to create a substring index

matched.');

commit;

/

--建立wordlist

Begin

ctx_ddl.drop_preference('mywordlist');

ctx_ddl.create_preference('mywordlist', 'basic_wordlist');

ctx_ddl.set_attribute('mywordlist','fuzzy_match','english'); --模糊匹配,英語

ctx_ddl.set_attribute('mywordlist','fuzzy_score','0'); --匹配得分

ctx_ddl.set_attribute('mywordlist','fuzzy_numresults','5000');

ctx_ddl.set_attribute('mywordlist','substring_index','true'); --左查詢,適用%to,%to%

ctx_ddl.set_attribute('mywordlist','stemmer','english'); --詞根

ctx_ddl.set_attribute('mywordlist', 'prefix_index', 'true'); --右查詢,適用t0%

End;

Create index indx_m_word on my_word(docs) indextype is ctxsys.context

parameters('wordlist mywordlist');

--例子

Select docs from my_word where contains(docs,'$match')>0 ; --詞根查詢

Select docs from my_word where contains(docs,'MA%')>0; --匹配查詢

 

3.6.2 document 上的例子

create table quick( quick_id number primary key, text varchar(80) );

--- insert a row with 10 expansions for 'tire%'

insert into quick ( quick_id, text )

values ( 1, 'tire tirea tireb tirec tired tiree tiref tireg tireh tirei tirej');

commit;

/

begin

Ctx_Ddl.Create_Preference('wildcard_pref', 'BASIC_WORDLIST');

ctx_ddl.set_attribute('wildcard_pref', 'wildcard_maxterms', 100) ;

end;

/

create index wildcard_idx on quick(text) indextype is ctxsys.context

parameters ('Wordlist wildcard_pref') ;

select quick_id from quick where contains ( text, 'tire%' ) > 0;

drop index wildcard_idx ;

begin

Ctx_Ddl.Drop_Preference('wildcard_pref');

Ctx_Ddl.Create_Preference('wildcard_pref', 'BASIC_WORDLIST');

ctx_ddl.set_attribute('wildcard_pref', 'wildcard_maxterms', 5) ;--限制最大的匹配數,如

果超過這個數量,查詢出現報錯

end;

/

create index wildcard_idx on quick(text) indextype is ctxsys.context

parameters ('Wordlist wildcard_pref') ;

select quick_id from quick where contains ( text, 'tire%' ) > 0;

 

3.6.3.參考腳本

--建立wordlist

begin

ctx_ddl.create_preference('mywordlist', 'BASIC_WORDLIST');

ctx_ddl.set_attribute('mywordlist','PREFIX_INDEX','TRUE'); --定義wordlist 的參數

end;

--刪除wordlist

begin

ctx_ddl.drop_preference('mywordlist');

3.7 Stoplist 屬性

Stoplist 允許屏蔽某些常用的詞,比如is,a,this,對這些詞進行索引用處不大,系統

默認會使用和數據庫語言相對應的停用詞庫(原文:Stoplists identify the words in your

language that are not to be indexed. In English, you can also identify stopthemes that are not to be indexed. By default, the system indexes text using the system-supplied stoplist that corresponds to your database language.),Oracle text 提供最常用的停用詞庫語言包括English, French, German,Spanish, Chinese, Dutch, and Danish

分別有basic_stoplist,empty_stoplist,default_stoplist,multi_stoplist 幾種類型

 

3.7.1 Basic_stoplist

建立用戶自定義的停用詞庫,文檔中關於stoplist 的介紹相當少,只有寥寥的數行

例子:

Create table my_stop (id number, docs varchar2(1000));

Insert into my_stop values (1, 'Stoplists identify the words in your language that are not

to be indexed.');

Insert into my_stop values (2, 'ou can also identify stopthemes that are not to be indexed');

Commit;

/

--建立basic stoplist

Begin

Ctx_ddl.create_stoplist('test_stoplist', 'basic_stoplist');

End;

Create index ind_m_stop on my_stop(docs) indextype is ctxsys.context

parameters ('stoplist test_stoplist');

Select * from my_stop where contains(docs, 'words') > 0;

Begin

Ctx_ddl.add_stopword('test_stoplist', 'language'); --添加停用詞

ctx_ddl.sync_index('ind_m_stop', '2m'); --同步索引

End;

Select * from my_stop where contains(docs, 'language') > 0; --添加停用詞,同步索引後發現還是

能查到,需要重新建立索引才能生效

Drop index ind_m_stop;

Create index ind_m_stop on my_stop(docs) indextype is ctxsys.context

parameters ('stoplist test_stoplist');

Select * from my_stop where contains(docs, 'language') > 0; --停用詞生效

添加停用詞,同步索引後發現還是能查到,需要重新建立索引才能生效。

 

3.7.2 Empty_stoplist

停用詞庫沒有任何停用詞,適用於不需要過濾的查詢中,如不需要過濾is this,a 等

 

3.7.3 Default_stoplist

建立basic_stoplist 後,裏面不包含任何的停用詞,而default_stoplist 在basic_stoplist 的基礎

上增加了預定義的默認停用詞,對於不同的語言,默認的停用詞庫數據也不一樣

例子:

Create table my_stop (id number, docs varchar2(1000));

Insert into my_stop values (1, 'Stoplists identify the words in your language that are not

to be indexed.');

Insert into my_stop values (2, 'ou can also identify stopthemes that are not to be indexed');

Commit;

/

--建立lexer,不同lexer 屬性會默認不同的停用詞庫

Begin

ctx_ddl.create_preference('test_b_lexer', 'basic_lexer');

End;

drop index ind_m_word;

--建立默認停用詞default_stoplist

Create index ind_m_word on my_stop(docs) indextype is ctxsys.context

Parameters ('lexer test_b_lexer stoplist ctxsys.default_stoplist');

--檢查默認詞庫中是否存在

Select * from my_stop where contains(docs, 'the') > 0;

Select * from my_stop where contains(docs, 'stopthemes') > 0;

--往默認詞庫中添加停用詞

conn ctxsys/ctxsys;

Begin

ctx_ddl.add_stopword('default_stoplist', 'stopthemes'); --增加停用詞

ctx_ddl.add_stopword('default_stoplist', 'words');

ctx_ddl.remove_stopword('default_stoplist', 'words');--刪除停用詞

End;

--添加後需重新建立索引才能生效

conn oratext/oratext;

drop index ind_m_word;

Create index ind_m_word on my_stop(docs) indextype is ctxsys.context

Parameters ('lexer test_b_lexer stoplist ctxsys.default_stoplist');

Select * from my_stop where contains(docs, 'words') > 0;

Select * from my_stop where contains(docs, 'stopthemes') > 0;

--相關數據字典

Select * from ctx_preferences where pre_name = 'DEFAULT_LEXER';

Select * from ctx_stopwords where spw_stoplist = 'DEFAULT_STOPLIST';

 

3.7.4 multi_stoplist

多語言停用詞,適用在文檔中包含不同的語言(A multi-language stoplist is useful when you use

the MULTI_LEXER to index a table that contains documents in different languages, such as

English, German, and Japanese)

增加停用詞時,可以爲停用詞指定某種語言,只對指定的語言生效,默認情況下停用詞對任

何語言都是生效的。

--建立multi_stoplist

begin

ctx_ddl.create_stoplist('multistop1', 'MULTI_STOPLIST');

ctx_ddl.add_stopword('multistop1', 'Die', 'german');

ctx_ddl.add_stopword('multistop1', 'Or', 'english');

end;

添加停用詞,同步索引後發現還是能查到,需要重新建立索引才能生效。

 

3.7.5 參考腳本

--建立stoplist:

Begin

Ctx_ddl.create_stoplist('test_stoplist', 'basic_stoplist');

End;

--刪除stoplist:

begin

ctx_ddl.drop_stoplist(' test_stoplist ');

end;

--增加停用詞

ctx_ddl.add_stopword('default_stoplist', 'stopthemes'); --增加停用詞

--刪除停用詞

                ctx_ddl.remove_stopword('default_stoplist', 'words');--刪除停用詞

 

3.8 Theme 主題查詢

主題查詢的概念是根據文檔的含義,而不僅僅是根據某個詞的匹配程度來返回查詢結果

的。比如查詢about(’US politics’)可能會返回‘US presidential elections’ 和 ‘US foreign

policy’之類的結果(原文:An ABOUT query is a query on a document theme. A document theme

is a concept that is sufficiently developed in the text. For example, an ABOUT query on US politics

might return documents containing information about US presidential elections and US foreign

policy. Documents need not contain the exact phrase US politics to be returned.)

10g 只支持兩種主題查詢語言:English,French

例子:

--在context 中啓用主題查詢

BEGIN

CTX_DDL.CREATE_PREFERENCE('TEST_ABOUT', 'BASIC_LEXER');

CTX_DDL.SET_ATTRIBUTE('TEST_ABOUT', 'INDEX_THEMES', 'YES');

CTX_DDL.SET_ATTRIBUTE('TEST_ABOUT', 'INDEX_TEXT', 'YES');

END;

CREATE INDEX IND_m_about ON my_about(DOCS) INDEXTYPE IS CTXSYS.CONTEXT

PARAMETERS ('LEXER CTXSYS.TEST_ABOUT');

--查詢

SELECT * FROM my_about WHERE CONTAINS(DOCS, 'ABOUT(US politics)') > 0;

               

3.9 Highlighting 高亮顯示

並不是說將內容高亮顯示,而是返回所有命中詞在文檔中的位置和命中詞本身的長度。

這樣用戶在得到文檔的同時,還得到了需要高亮顯示的內容的長度和偏移量,真正的顯示工作需要由用戶來完成(原文:In Oracle Text query applications, you can present selected

documents with query terms highlighted for text queries or with themes highlighted for ABOUT

queries)

例子:

Create table my_high (id number primary key, docs varchar2(1000));

insert into my_high values (1, 'this is a oracle text example. And oracle is the key word.');

insert into my_high values (2, '<title>oracle text</title>

2 <body>this is a oracle ctx_doc hightlight example.</body>');

commit;

/

--建立索引

create index ind_m_high on my_high(docs) indextype is ctxsys.context;

--返回結果的偏移量

set serverout on

declare

v_restab ctx_doc.highlight_tab;

begin

ctx_doc.highlight('ind_m_high', 1, 'oracle', v_restab, true);

for i in 1..v_restab.count loop

dbms_output.put_line('begin with: ' || v_restab(i).offset || ' length: ' || v_restab(i).length);

end loop;

end;

begin with: 11 length: 6

begin with: 36 length: 6

參考:

http://yangtingkun.itpub.net/post/468/212718

http://download.oracle.com/docs/cd/B19306_01/text.102/b14217/view.htm

 

3.10常用的腳本

3.10.1.刪除preference:

begin

ctx_ddl.drop_preference('my_lexer');

end;

 

3.10.2.索引重建:

ALTER INDEX newsindex REBUILD PARAMETERS('replace lexer my_lexer');

 

3.10.3 同步索引

begin

ctx_ddl.sync_index('myindex', '2M');

end;

或通過後臺設置同步腳本:

$ORACLE_HOME/ctx/sample/script/drjobdml.sql --後臺同步腳本(9i 中有,10g 不知道放哪兒了,文檔有問題)

SQL> @drjobdml myindex 360 --表示以週期360 分鐘同步索引myindex

或通過創建索引加參數實現

--表示每小時同步一次,內存16m

CREATE INDEX IND_m_high ON my_high(DOCS) INDEXTYPE IS CTXSYS.CONTEXT

parameters ('sync (EVERY "TRUNC(SYSDATE)+ 1/24") memory 16m ') parallel 2 online;

(確認這個時間間隔內索引同步能完成,否則,sync job 將處於掛起狀態)

--還可以是

sync (manual) --手工同步,默認

sync (on commit) --dml 後立即同步

--通過job 定義同步

declare

job number;

begin

dbms_job.submit(job,

'ctx_ddl.sync_index(''ind_m_high'');', --索引名

interval => 'SYSDATE+1/1440'); --1 分鐘一次

commit;

dbms_output.put_line('job ' || job || ' has been submitted.');

end;

 

 

3.10.4.索引碎片:

剛開始建立索引後,DOG 可能是如下的條目

DOG DOC1 DOC3 DOC5

新的文檔增加到表後,新行會同步到索引中去,假設新文檔中Doc7 中的DOG 被同步到索引中去,DOG

可能變成如下條目

DOG DOC1 DOC3 DOC5

DOG DOC7

隨後的DML 操作可能變成:

DOG DOC1 DOC3 DOC5

DOG DOC7

DOG DOC9

DOG DOC11

這就產生了碎片,需要進行索引的優化

查看索引碎片

create table output (result CLOB);

declare

x clob := null;

begin

ctx_report.index_stats('idx_auction', x);

insert into output values (x);

commit;

dbms_lob.freetemporary(x);

end;

select * from output

 

3.10.5索引優化:

快速fast 優化和全部full 優化的區別是,快速優化不會刪除沒用的、過期的數據,而full 會刪除老的數據(deleted rows)

--快速優化

begin

ctx_ddl.optimize_index('myidx','FAST');

end;

--全部優化

begin

ctx_ddl.optimize_index('myidx','FULL');

end;

--對單個記號進行優化,默認是full 模式

begin

ctx_ddl.optimize_index('myidx','token', TOKEN=>'Oracle');

end;

 

3.10.6.Online 參數限制:

at the very beginning or very end of this process, dml might fail.

online is supported for context indexes only.

online cannot be used with parallel.

--online 索引的時候後面必須要加parameters,否則會失敗

alter index IND_m_high rebuild online parameters ('sync memory 16m' )

 

3.10.7.更改索引的屬性,但不進行索引重建

Replaces the existing preference class settings, including SYNC parameters, of the index with

the settings from new_preference. Only index preferences and attributes are replaced. The index is

not rebuilt.

ALTER INDEX myidx REBUILD PARAMETERS('replace metadata transactional');

alter index idx_auction_db1 rebuild PARAMETERS('REPLACE METADATA SYNC(ON COMMIT)') ;

參考文檔:

http://download.oracle.com/docs/cd/B19306_01/text.102/b14218/csql.htm#CIHBFDCE

 

3.10.8.Score:

--表示得分,分值越高,表示查到的數據越精確

SELECT SCORE(1), id, text FROM docs WHERE CONTAINS(text, 'oracle', 1) > 0;

--根據得分來排序

SELECT SCORE(1), title from news WHERE CONTAINS(text, 'oracle', 1) > 0 AND issue_date >=

('01-OCT-97')

ORDER BY SCORE(1) DESC;

 

3.10.9.分析表:

ANALYZE TABLE <table_name> COMPUTE STATISTICS;

ANALYZE TABLE <table_name> ESTIMATE STATISTICS 1000 ROWS;

ANALYZE TABLE <table_name> ESTIMATE STATISTICS 50 PERCENT;

ANALYZE TABLE <table_name> DELETE STATISTICS;

 

3.10.10.數據字典表:

查看系統默認的oracle text 參數

Select pre_name, pre_object from ctx_preferences

查詢dml 操作後索引爲同步

SELECT pnd_index_name, pnd_rowid, to_char(pnd_timestamp, 'dd-mon-yyyy hh24:mi:ss')

timestamp FROM ctx_user_pending;

查看錯誤記錄表

select * from CTX_USER_INDEX_ERRORS

 

3.10.11.Php,Jsp 應用oracle text:

http://download.oracle.com/docs/cd/B19306_01/text.102/b14217/acase.htm

 

3.10.12.邏輯操作符:

          

 

-- or 操作符

Select id, text from docs where contains(text, 'city or state ') > 0;

--and 操作符

Select id, text from docs where contains(text, 'city and state ') > 0;

或是

Select id, text from docs where contains(text, 'city state ') > 0;

 

 

3.10.13.索引優化問題

--先看個例子

SQL> exec ctx_ddl.optimize_index('idx_auction_db1','FULL');

PL/SQL procedure successfully completed.

Elapsed: 00:16:16.77

索引優化相當的慢,200 萬的數據建立context 索引需要不到5 分鐘,而優化索引居然要16 分鐘,這麼慢

的優化速度對一個具有幾億表的數據是很難接受的的。剛開始我以爲這是oracle 的一個bug,後來查到了

一些文檔。Oracle10g 引進了rebuild 優化參數,速度還是很快的。

SQL> exec ctx_ddl.optimize_index('idx_auction_db1','rebuild') ;

PL/SQL procedure successfully completed.

 

 

3.10.14 事務查詢

索引可能不是實時進行同步的,但是查詢又要求實時的。

--更改索引爲事務性,查詢再找索引時還會dr$unindexed 表,把滿足條件還未索引的記錄找出來

alter index idx_auction_db1 rebuild parameters('replace metadata transactional')

例子:

select count(*) from table where contains(text, 'someword') > 0; -- 0 hits

insert into table values ('someword');

select count(*) from table where contains(text, 'someword') > 0; -- 1 hit (the one we just

entered)

rollback;

select count(*) from table where contains(text, 'someword') > 0; -- 0 hit

僅僅是對某個session 啓用

exec ctx_query.disable_transactional_query := TRUE;

 

參考文檔:

http://tahiti.oracle.com

http://yangtingkun.itpub.net

http://epub.itpub.net/4/1.htm

http://www.oracle.com/global/cn/oramag/oracle/04-sep/o54text.html

http://www.oracle.com/technology/products/text/x/10g_tech_overview.html

http://forums.oracle.com/forums/thread.jspa?messageID=1958708

 

 

4、操作實例

4.1 單列與多列支持中文檢索

Create table mytable1(id number primary key, doc1 varchar2(400),doc2 clob,doc3 clob);

 

Insert into mytable1 values(1,'今天的天氣很不錯,我想去逛街','今天是星期天,不用上班。天天好心情','明天是星期一,要上班。心情不好');

Insert into mytable1 values(2,'天是藍色的,萬里無雲。天氣非常好。','天是多雲的,天氣看起來要下雨了。不適宜出門','天正在下雨,大雨傾盆。不能出門。');

Insert into mytable1 values(3,'this is a text','this is a word','this is a pdf');

Commit;

 

--先刪除引用

begin

ctx_ddl.drop_preference('my_chinese_vgram_lexer');

ctx_ddl.drop_preference('my_chinese_lexer');

end;

 

--支持中文分詞

Begin

ctx_ddl.create_preference('my_chinese_vgram_lexer', 'chinese_vgram_lexer');

ctx_ddl.create_preference('my_chinese_lexer', 'chinese_lexer');

End;

 

--先刪除引用

begin

ctx_ddl.drop_preference('my_multi');

end;

--多列查詢,如果僅僅是單列,則不用設置這個類型

Begin

Ctx_ddl.create_preference('my_multi', 'multi_column_datastore');

Ctx_ddl.set_attribute('my_multi', 'columns', 'doc1, doc2, doc3');

End;

 

 

drop index myindex;

 

--單列查詢,支持中文的索引建立

Create index myindex on mytable(docs)

indextype is ctxsys.context

parameters ('datastore ctxsys.default_datastore lexer foo.my_chinese_lexer')

 

drop index idx_mytable;

--多列查詢,支持中文的索引的建立

Create index idx_mytable on mytable1(doc1)indextype is ctxsys.context

parameters('datastore my_multi lexer foo.my_chinese_lexer');

 

--chinese_lexer詞法分析器下的結果,三列都可以查詢

Select * from mytable1 where contains(doc1, '今天')>0;  --檢索到第一條數據

Select * from mytable1 where contains(doc1, '不適宜')>0; --檢索到第二條數據

Select * from mytable1 where contains(doc1, '適宜')>0; --檢索不到數據,他的分詞技術太簡單,將‘不適宜’作爲一個詞了

Select * from mytable1 where contains(doc1, '出門')>0;  --檢索到第二條數據

Select * from mytable1 where contains(doc1, 'this is a word')>0;  --檢索到第三條數據,中英文適用

 

 

--chinese_vgram_lexer詞法分析器下的結果,

--chinese_vgram_lexer詞法分析器雖然沒那麼智能,但檢索結果往往比較符合我們的要求,

--如:“不適宜”這個詞語應該拆分爲“不適宜”和“適宜”兩個詞語,而不是單獨的作爲一個詞語,

--chinese_vgram_lexer可以查詢的到,而chinese_lexer不可以。

drop index idx_mytable;

--多列查詢,支持中文的索引的建立

Create index idx_mytable on mytable1(doc1)indextype is ctxsys.context

parameters('datastore my_multi lexer foo.my_chinese_vgram_lexer');

 

--chinese_vgram_lexer詞法分析器下的結果,三列都可以查詢

Select * from mytable1 where contains(doc1, '今天')>0;  --檢索到第一條數據

Select * from mytable1 where contains(doc1, '不適宜')>0; --檢索到第二條數據

Select * from mytable1 where contains(doc1, '適宜')>0; --檢索到第二條數據,這個分詞雖然效率低點,但檢索結果還可以

Select * from mytable1 where contains(doc1, '出門')>0;  --檢索到第二條數據

Select * from mytable1 where contains(doc1, 'this is a word')>0;  --檢索到第三條數據,中英文適用

 

 

--對於多列查詢,更新列操作

--只更新從表,看是否能查到更新的信息

Update mytable1 set doc2='adladlhadad this datastore when your text is stored test' where id=2;

 

--同步更新索引

Begin

Ctx_ddl.sync_index('idx_mytable');

End;

--可見,雖然你檢索是三個列,但是你更新的不是索引對應的那列(doc1),同步了索引也是不起作用的

Select * from mytable1 where contains(doc1,'adladlhadad')>0; --沒有記錄

 

--更新與doc1列原來相同內容(實際內容不變,只有操作而已)

Update mytable1 set doc1='天是藍色的,萬里無雲。天氣非常好。' where id=2;

 

--再同步更新索引

Begin

Ctx_ddl.sync_index('idx_mytable');

End;

 

--再查詢一次

Select * from mytable1 where contains(doc1,'adladlhadad')>0; --有結果,可見,對於其他查詢的列(非索引對應的列)的更新操作,可以連同索引對應的列一起更新,只是不改變索引的內容即可做到同步索引就可以出現效果了。

4.2 本地磁盤檢索

create table mytable3(id number primary key, docs varchar2(2000));

 

insert into mytable3 values(111555,'1.txt');

 

insert into mytable3 values(111556,'1.doc');

 

insert into mytable3 values(111557,'1.xls');

 

insert into mytable3 values(111558,'1.pdf');

 

insert into mytable3 values(111559,'2.txt');

 

insert into mytable3 values(111560,'2.doc');

 

insert into mytable3 values(111561,'2.xls');

 

insert into mytable3 values(111562,'2.pdf');

 

commit;

 

 

--先刪除引用

begin

ctx_ddl.drop_preference('COMMON_DIR');

end;

 

--建立 file datastore

begin

ctx_ddl.create_preference('COMMON_DIR','FILE_DATASTORE');

ctx_ddl.set_attribute('COMMON_DIR','PATH','D:\search');

end;

 

--先刪除索引

drop index myindex3;

--建立索引,8個文件,內容簡單,耗時1.5s

create index myindex3 on mytable3(docs) indextype is ctxsys.context parameters ('datastore COMMON_DIR lexer foo.my_chinese_lexer');

 

select * from mytable3 where contains(docs,'text')>0; --查詢,支持txt

select * from mytable3 where contains(docs,'pdf')>0; --查詢,支持pdf

select * from mytable3 where contains(docs,'excel')>0; --查詢,支持excel

select * from mytable3 where contains(docs,'word')>0; --查詢,支持doc

select * from mytable3 where contains(docs,'文本')>0; --查詢,支持中文

select * from mytable3 where contains(docs,'文檔')>0; --查詢,支持中文

select * from mytable3 where contains(docs,'閱讀')>0; --查詢,支持中文pdf

select * from mytable3 where contains(docs,'這是Excel')>0; --查詢,支持中文

 

--暫時測試支持doc,txt,xls,pdf

 

--更新了文件內容2.txt

select * from mytable3 where contains(docs,'這個測試用的文本')>0; --查詢無更新好數據

--不同步索引,無效

--同步更新索引

Begin

Ctx_ddl.sync_index('myindex3');

End;

--再次查詢

select * from mytable3 where contains(docs,'測試')>0; --還是無效

 

--用相同的值取代2.txt然後再同步索引

Update mytable3 set docs='2.txt' where id=111559;

 

--再同步索引

--同步更新索引

Begin

Ctx_ddl.sync_index('myindex3');

End;

--再次查詢

select * from mytable3 where contains(docs,'測試')>0; --結果出現,可見,單更新文件內容,同步索引是無效的,索引認的是數據庫紀錄,數據庫紀錄改變,索引纔會更新

 

--新增加文件,結果雷同。關鍵是要更新數據庫紀錄,即使改了文件內容,也要用相同的值update數據庫紀錄一次。

4.3 檢索結果高亮顯示

Create table my_high (id number primary key, docs varchar2(1000));

insert into my_high values (1, 'this is a oracle text example. And oracle is the key word.');

insert into my_high values (2, '<title>oracle text</title><body>this is a oracle ctx_doc hightlight example.</body>');

commit;

/

--建立索引

create index ind_m_high on my_high(docs) indextype is ctxsys.context;

--返回結果的偏移量

set serverout on

declare

v_restab ctx_doc.highlight_tab;

begin

ctx_doc.highlight('ind_m_high', 1, 'oracle', v_restab, true);

for i in 1..v_restab.count loop

dbms_output.put_line('begin with: ' || v_restab(i).offset || ' length: ' || v_restab(i).length);

end loop;

end;

/

begin with: 11 length: 6

begin with: 36 length: 6

 

ctx_doc.highlight參數說明:

ctx_doc.highlight(索引,數據庫中的ID, 搜索關鍵字, 指明返回的偏移量是針對純文本格式還是針對HTML格式, true);

true or false: 對比PLAINTEXT設置爲FALSE和TRUE的區別可以發現,對於HTML所有的標識部分,Oracle統一認爲長度等於2。

對於True: <title>oracle text</title><body>this is a oracle ctx_doc hightlight example.</body>,<title>認爲是2個長度,false的話就全部紀錄,認爲總共有7個字符長度。

 

                要在sqlplus執行

 

4.4 具體測試

               

 

 

4.4.1 基本的全文檢索

--先刪除引用

begin

ctx_ddl.drop_preference('my_chinese_vgram_lexer');

ctx_ddl.drop_preference('my_chinese_lexer');

end;

 

--支持中文分詞

Begin

ctx_ddl.create_preference('my_chinese_vgram_lexer', 'chinese_vgram_lexer');

ctx_ddl.create_preference('my_chinese_lexer', 'chinese_lexer');

End;

Begin

Ctx_ddl.create_preference('F_DOCNEWS_Preference', 'multi_column_datastore');

Ctx_ddl.set_attribute('F_DOCNEWS_Preference', 'columns', 'F_CONTENT,F_DESCRIPTION,F_TITLE');

End;

drop index f_content_index;

Create index f_content_index on T_DOCNEWS(F_CONTENT)

indextype is ctxsys.context

parameters('datastore F_DOCNEWS_Preference lexer foo.my_chinese_lexer');

Select * from T_DOCNEWS where contains(F_CONTENT,'菲律賓')>0; --有結果,

 

 

4.4.2 帶動態摘要的高亮全文檢索

--先刪除引用

begin

ctx_ddl.drop_preference('my_chinese_vgram_lexer');

ctx_ddl.drop_preference('my_chinese_lexer');

end;

 

--支持中文分詞

Begin

ctx_ddl.create_preference('my_chinese_vgram_lexer', 'chinese_vgram_lexer');

ctx_ddl.create_preference('my_chinese_lexer', 'chinese_lexer');

End;

 

--先刪除索引

drop index f_content_index;

 

--新建索引,默認屬性,無過濾器,支持中文高級分詞

Create index f_content_index on T_DOCNEWS(F_CONTENT)

indextype is ctxsys.context

parameters('datastore ctxsys.default_datastore filter ctxsys.null_filter section group

ctxsys.html_section_group lexer foo.my_chinese_lexer');

 

 

 

 

--以下開始準備建立存儲過程,先定義數組類型

CREATE or replace TYPE f_content_arr AS OBJECT(

id NUMBER ,

url varchar2(255),

title varchar2(255),

abstractcontent varchar2(255)

);

 

--定義數組變量

CREATE or replace type f_content_arr_re as table of f_content_arr;

 

--定義存儲過程

create or replace procedure f_content_pro (keyword in varchar,v_cfjg out f_content_arr_re) is

v_restab ctx_doc.highlight_tab;

begin

DECLARE

i number;

s clob;

startnum number;

endnum number;

v_res_fun T_DOCNEWS%rowTYPE;

cursor c_fun is

select *  from T_DOCNEWS where contains(F_CONTENT,keyword)>0;

BEGIN

i := 0;

v_cfjg := f_content_arr_re();

open c_fun;

LOOP

fetch c_fun

into v_res_fun;

EXIT WHEN c_fun%NOTFOUND;

i := i + 1;

s := v_res_fun.F_CONTENT;

v_cfjg.EXTEND;

ctx_doc.highlight('f_content_index', v_res_fun.F_ID, keyword, v_restab, false);

--只取第一個,沒有loop循環

startnum:=v_restab(1).offset;

if v_restab(1).offset > 30 then

   begin

        startnum := v_restab(1).offset-30 ;

   end;

end if;

if v_restab(1).offset <= 30 then

   begin

        startnum := 1 ;

   end;

end if;

if length(s)-v_restab(1).offset > 30 then

   begin

        endnum := v_restab(1).offset+30 ;

   end;

end if;

if length(s)-v_restab(1).offset <= 30 then

   begin

        endnum := length(s) ;

   end;

end if;

v_cfjg(v_cfjg.count) := f_content_arr(v_res_fun.F_ID,v_res_fun.F_URL,v_res_fun.F_TITLE,substr(s,startnum,endnum-startnum));

dbms_output.new_line();

END LOOP;

end;

EXCEPTION

WHEN TOO_MANY_ROWS THEN

DBMS_OUTPUT.PUT_LINE('TOO_MANY_ROWS');

WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE(sqlerrm);

end f_content_pro;

 

--在此,全文檢索存儲過程定義完畢

 

 

 

--以下是sqlplus調用

 

declare

   s f_content_arr_re;

 begin   

   f_content_pro('菲律賓',s);    

 END; 

 

 

       Java後臺調用存儲過程並返回參數代碼:

            public ArrayList<DocNews> search(String keyword) {

                  ArrayList<DocNews> list = new ArrayList<DocNews>();

                  Connection conn = null;

                  ResultSet rs = null;

                  CallableStatement stmt = null;

                  DocNews docnews;

                  try {

                        conn = DBPool.getConnection();

                        stmt = null;

               String procName = new StringBuffer().append("{ call f_content_pro(?,?) } ").toString();

                        stmt = conn.prepareCall(procName);

                        stmt.setString(1, keyword);

                        stmt.registerOutParameter(2, Types.ARRAY, "F_CONTENT_ARR_RE");

                        stmt.execute();

                        ARRAY arr = (ARRAY) stmt.getArray(2);

                        rs = arr.getResultSet();

                        while (rs.next()) {

                              STRUCT struct = (STRUCT) rs.getObject(2);

                              Object[] obs = struct.getAttributes();

                              docnews = new DocNews();

                              docnews.setId(((BigDecimal)obs[0]).longValue());

                              docnews.setUrl((String)obs[1]);

                              docnews.setTitle((String)obs[2]);

                              docnews.setAbstractcontent((String)obs[3]);

                              list.add(docnews);

                        }

                        if (stmt != null) {

                              stmt.close();

                        }

                        if (conn != null) {

                              conn.close();

                        }

                  } catch (Exception e) {

                        e.printStackTrace();

                  }

                  return list;

         }

 

       注:在java中調用方法,除了在項目里加入class12.jar包以外,還需要加入Oracle自帶的orai18n.jar包,如果僅僅是執行main方面,則可以,但如果是web項目,則要將orai18n.jar包加入到jdk的%jdk%\jre\lib\ext目錄中才行。如果沒有orai18n.jar這個包會造成檢索調用存儲過程返回結果是亂碼(???三個問號)。

 

4.4.3 檢索簡單界面圖

 

 

5.檢索性能

                        執行以下索引

Create index f_content_index on T_DOCNEWS(F_CONTENT)

indextype is ctxsys.context

parameters('datastore F_DOCNEWS_Preference lexer foo.my_chinese_lexer');

總共5272條新聞,總耗時61s

合計約一分鐘5000條

 

查詢僅需200多毫秒

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章