oracle全文索引之FILTER

介绍完Oracle全文索引的DATASTORE属性,继续介绍Oracle的FILTER属性。

Oracle全文索引的FILTER属性主要是针对具有一定格式的文档,Oracle根据FILTER的设定来过滤那些不属于文章内容的部分。

FILTER属性包含的属性有:CHARSET_FILTER、INSO_FILTER、NULL_FILTER、USER_FILTER、PROCEDURE_FILTER几种。



这里仍然从FILTER的最简单属性NULL_FILTER开始介绍:

SQL> CREATE TABLE T (ID NUMBER, DOCS VARCHAR2(4000));

表已创建。

SQL> INSERT INTO T VALUES (1, 'This is a sample for Oracle TEXT.');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, 'This is a null filter sample');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('FILTER CTXSYS.NULL_FILTER');

索引已创建。

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'TEXT') > 0;

ID DOCS
---------- ----------------------------------------
1 This is a sample for Oracle TEXT.

上面就是一个简单的NULL_FILTER的例子,所谓NULL_FILTER就是不使用过滤。Oracle推荐对于文本、HTML和XML文件不使用过滤。

Oracle的FILTER的默认值和索引列的字段类型,以及DATASTORE的属性有关。如果是存储在数据库中的列,且列的类型为VARCHAR2、CHAR、CLOB,则Oracle会使用NULL_FILTER作为FILTER的默认属性。

其实上面这个例子和不指定FILTER是等价的。

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT;

索引已创建。

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'FILTER') > 0;

ID DOCS
---------- ----------------------------------------
2 This is a null filter sample

 

 

这篇文章继续介绍全文索引的FILTER属性,介绍Oracle的INSO_FILTER属性。

Oracle的全文索引除了可以支持文本文件外,还可以支持多种文档格式,对于这些文档格式,在建立索引的时候需要指定INSO_FILTER参数,使用这个过滤参数,Oracle的全文索引可以识别绝大部分的常见文档,比如:word、pdf等。

下面看一个索引文档的例子:

SQL> conn myuser/myuser
Connected.
SQL> CREATE TABLE T (ID NUMBER, DOCS VARCHAR2(1000));

Table created.

SQL> INSERT INTO T VALUES (1, 'pdf.pdf');

1 row created.

SQL> INSERT INTO T VALUES (2, 'doc1.doc');

1 row created.

SQL> commit;

Commit complete.

SQL> begin
2 CTX_DDL.CREATE_PREFERENCE('TEST_FILE', 'FILE_DATASTORE');
3 CTX_DDL.SET_ATTRIBUTE('TEST_FILE', 'PATH', '/home/oracle');
4 END;
5 /

PL/SQL procedure successfully completed.

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('DATASTORE TEST_FILE FILTER CTXSYS.INSO_FILTER');

Index created.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID
----------
DOCS
--------------------------------------------------------------------------------
1
pdf.pdf

2
doc1.doc


SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'sina.com')>0;

ID
----------
DOCS
--------------------------------------------------------------------------------
1
pdf.pdf

下面试试如果修改文档的内容,是否还能查询得到?
先在doc1.doc中新入一行"ericlu"字符。

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ericlu')>0;

no rows selected

SQL> exec CTX_DDL.SYNC_INDEX('IND_T_DOCS');

PL/SQL procedure successfully completed.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ericlu')>0;

no rows selected

同步过索引依然找不到

SQL> drop index IND_T_DOCS;

Index dropped.

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('DATASTORE TEST_FILE FILTER CTXSYS.INSO_FILTER');

Index created.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ericlu')>0;

ID
----------
DOCS
--------------------------------------------------------------------------------
2
doc1.doc

重建后可以找到,下面试了rebuild也可以的。

先在doc1.doc中加入"my cups"字符。

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'my cups')>0;

no rows selected

SQL> alter index IND_T_DOCS rebuild;

Index altered.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'my cups')>0;

ID
----------
DOCS
--------------------------------------------------------------------------------
2
doc1.doc


FILTER的默认值并不是一成不变的,这个默认值会受索引字段类型和DATASTORE的类型的影响。在上一篇文章中
的测试中,对于存储在数据库中的VARCHAR2、CHAR和CLOB字段中的数据,Oracle自动选择了NULL_FILTEL。在这
里DATASTORE的属性为FILE_DATASTORE,则Oracle会默认选择 INSO_FILTER作为默认值。
SQL> DROP INDEX IND_T_DOCS;

Index dropped.

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('DATASTORE TEST_FILE FILTER CTXSYS.INSO_FILTER');

Index created.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID
----------
DOCS
--------------------------------------------------------------------------------
1
pdf.pdf

2
doc1.doc


SQL> DROP INDEX IND_T_DOCS;

Index dropped.

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('DATASTORE TEST_FILE');

Index created.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID
----------
DOCS
--------------------------------------------------------------------------------
1
pdf.pdf

2
doc1.doc

可以发现默当DATASTORE的属性为FILE_DATASTORE,Oracle会选择 INSO_FILTER作为默认值。

 

 

这篇文章继续介绍全文索引的FILTER属性,介绍对不同类型的数据采用不同类型的FILTER属性的方法。

如果Oracle索引的文档包括多种类型,比如doc文件、html文件、pdf文件、纯文本文件等等。由于Oracle不建议对HTML、XML和纯文本文件使用INSO_FILTER,因此没有一个统一适用的FILTER属性适合所有的文档。


Oracle提供了一种FORMAT列的方法,通过设置FORMAT列的内容可以通知Oracle建立何种FILTER甚至是不建立索引。

下面看一个简单的例子:

[oracle@rhel140 ~]$ sqlplus myuser/myuser

SQL*Plus: Release 10.2.0.1.0 - Production on Sun May 17 21:35:01 2009

Copyright (c) 1982, 2005, Oracle. All rights reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> CREATE TABLE T (ID NUMBER, TYPE VARCHAR2(6), DOCS VARCHAR2(100));

Table created.

SQL> INSERT INTO T VALUES (1, 'BINARY', 'pdf.pdf');

1 row created.

SQL> INSERT INTO T VALUES (2, 'TEXT', 'OUTPUT.TXT');

1 row created.

SQL> INSERT INTO T VALUES (3, 'IGNORE', 'doc1.doc');

1 row created.

SQL> COMMIT;

Commit complete.

SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_FILE', 'FILE_DATASTORE');
3 CTX_DDL.SET_ATTRIBUTE('TEST_FILE', 'PATH', '/home/oracle');
4 END;
5 /

PL/SQL procedure successfully completed.

SQL> CREATE INDEX IND_T_DOCS ON T (DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('DATASTORE TEST_FILE FILTER CTXSYS.INSO_FILTER FORMAT COLUMN TYPE');

Index created.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID TYPE
---------- ------
DOCS
--------------------------------------------------------------------------------
2 TEXT
OUTPUT.TXT

1 BINARY
pdf.pdf


'doc1.doc'文档中有'ORACLE'字符串没有被查到,是因为'IGNORE'起了作用。
发现表T的列TYPE的值很重要,是因为FORMAT COLUMN指定为“TYPE”列,设置为BINARY的文档使用INST_FILTER,设置为TEXT的文档使用NULL_FILTER,设置为IGNORE的文档不进行索引。


SQL> update t set type='BINARY' where id=3;

1 row updated.

SQL> commit;

Commit complete.

SQL> exec ctx_ddl.sync_index('IND_T_DOCS');

PL/SQL procedure successfully completed.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID TYPE
---------- ------
DOCS
--------------------------------------------------------------------------------
2 TEXT
OUTPUT.TXT

1 BINARY
pdf.pdf

sync过还是查询不到,需要做rebuild

SQL> alter index IND_T_DOCS rebuild;

Index altered.

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, 'ORACLE') > 0;

ID TYPE
---------- ------
DOCS
--------------------------------------------------------------------------------
1 BINARY
pdf.pdf

2 TEXT
OUTPUT.TXT

3 BINARY
doc1.doc

这篇文章继续介绍全文索引的FILTER属性,介绍全文索引的PROCEDURE_FILTER属性。

 

 

对于一些复杂的需求,Oracle 自定义的FILTER可能并不合适,Oracle支持用户自己编写用于FILTER的程序。Oracle提供两种方式,一种是USER_FILTER一种 是PROCEDURE_FILTER。USER_FILTER是用户编译好的命令行程序,而PROCEDURE_FILTER是调用用户编写的存储过程。


下面举一个PROCEDURE_FILTER的例子,在例子中被索引的文档为纯文本格式,要求是不索引文档中注释部分的内容。这种要求是预定义FILTER无法达到的,只能通过PROCEDURE_FILTER的方式来解决,下面看这个例子:

SQL> CREATE TABLE T (ID NUMBER, DOCS VARCHAR2(4000));

表已创建。

SQL> INSERT INTO T VALUES (1, 'This is a example for procedure filter.
2 In the this example, the words in comments are not indexed.');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, '--This line should not be indexed.
2 /* And this two lines
3 should not be indexed too. */
4 Only this line is the real context.');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> CREATE INDEX IND_T_DOCS ON T(DOCS) INDEXTYPE IS CTXSYS.CONTEXT;

索引已创建。

SQL> SELECT ID FROM T WHERE CONTAINS(DOCS, 'INDEXED') > 0;

ID
----------
2
1

对于普通的索引,是不会区分注释内容和正文内容的。

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> CREATE OR REPLACE FUNCTION F_COMMENTS (P_STR IN VARCHAR2, P_FLAG IN NUMBER) RETURN VARCHAR2 AS
2 V_POSITION1 NUMBER;
3 V_POSITION2 NUMBER;
4 BEGIN
5 IF P_FLAG = 0 THEN
6 V_POSITION1 := INSTR(P_STR, '/*');
7 V_POSITION2 := INSTR(P_STR, '--');
8 IF V_POSITION1 = 0 THEN
9 V_POSITION1 := 40000;
10 END IF;
11 IF V_POSITION2 = 0 THEN
12 V_POSITION2 := 40000;
13 END IF;
14 IF V_POSITION1 < V_POSITION2 THEN
15 RETURN SUBSTR(P_STR, 1, V_POSITION1 - 1) || F_COMMENTS(SUBSTR(P_STR, V_POSITION1 + 2), 1);
16 ELSIF V_POSITION2 < V_POSITION1 THEN
17 RETURN SUBSTR(P_STR, 1, V_POSITION2 - 1) || F_COMMENTS(SUBSTR(P_STR, V_POSITION2 + 2), 2);
18 ELSE
19 RETURN P_STR;
20 END IF;
21 ELSIF P_FLAG = 1 THEN
22 RETURN F_COMMENTS(SUBSTR(P_STR, INSTR(P_STR, '*/') + 2), 0);
23 ELSIF P_FLAG = 2 THEN
24 V_POSITION2 := INSTR(P_STR, CHR(10));
25 IF V_POSITION2 != 0 THEN
26 RETURN F_COMMENTS(SUBSTR(P_STR, V_POSITION2 + 1), 0);
27 ELSE
28 RETURN NULL;
29 END IF;
30 END IF;
31 END;
32 /

函数已创建。

SQL> CREATE OR REPLACE PROCEDURE P_MYFILTER (P_INSTR IN VARCHAR2, P_OUTSTR IN OUT VARCHAR2) AS
2 BEGIN
3 P_OUTSTR := F_COMMENTS(P_INSTR, 0);
4 END;
5 /

过程已创建。

SQL> CONN CTXSYS/CTXSYS@YANGTK
已连接。
SQL> CREATE OR REPLACE PROCEDURE P_TESTFILTER(P_INSTR IN VARCHAR2, P_OUTSTR IN OUT VARCHAR2) AS
2 BEGIN
3 YANGTK.P_MYFILTER(P_INSTR, P_OUTSTR);
4 END;
5 /

过程已创建。

SQL> GRANT EXECUTE ON P_TESTFILTER TO YANGTK;

授权成功。

SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_PROCEDURE_FILTER', 'PROCEDURE_FILTER');
3 CTX_DDL.SET_ATTRIBUTE('TEST_PROCEDURE_FILTER', 'PROCEDURE', 'P_TESTFILTER');
4 CTX_DDL.SET_ATTRIBUTE('TEST_PROCEDURE_FILTER', 'INPUT_TYPE', 'VARCHAR2');
5 CTX_DDL.SET_ATTRIBUTE('TEST_PROCEDURE_FILTER', 'OUTPUT_TYPE', 'VARCHAR2');
6 END;
7 /

PL/SQL 过程已成功完成。

SQL> CONN YANGTK/YANGTK@YANGTK
已连接。
SQL> CREATE INDEX IND_T_DOCS ON T(DOCS) INDEXTYPE IS CTXSYS.CONTEXT
2 PARAMETERS ('FILTER CTXSYS.TEST_PROCEDURE_FILTER');

索引已创建。

SQL> SELECT ID FROM T WHERE CONTAINS(DOCS, 'INDEXED') > 0;

ID
----------
1

PROCEDURE_FILTER属性的设置方法和USER_DATASTORE属性的设置方法十分类似,都是必须使用CTXSYS用户来调用用户编译的过程。且CTXSYS用户封装的过程还必须授权给建立索引的用户。

使用自定义的过程来进行过滤,将文档内容中的注释内容过滤掉,索引查询的内容已经不包含注释的内容了。

对于如何判断注释内容,可以参考:http://yangtingkun.itpub.net/post/468/184024

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值