oracle全文索引之LEXER

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

Oracle全文索引的LEXER属性用于处理各种不同的语言。最基本的英文使用BASE_FILTER,而如果需要使用中文则可以使用CHINESE_VGRAM_LEXER或CHINESE_LEXER。
这篇文章简单说明BASIC_LEXER属性。BASIC_LEXER属性支持多种语言,比如英语、德语、荷兰语、挪威语、瑞典语等等。

BASIC_LEXER除了支持多种语言,还可以设置多种属性。比如这个例子中介绍的索引的大小写设置:

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

表已创建。

SQL> INSERT INTO T VALUES (1, 'This is a example for the basic lexer');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, 'And we make a example for a mixed spell indexs.');

已创建 1 行。

SQL> INSERT INTO T VALUES (3, 'So the word in UPPER format must be query in UPPER');

已创建 1 行。

SQL> INSERT INTO T VALUES (4, 'And Mixed Spell Word must be Query in Mixed.');

已创建 1 行。

SQL> COMMIT;

提交完成。

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

索引已创建。

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

ID
----------
4
2

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> CONN CTXSYS/CTXSYS@YANGTK
已连接。
SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_BASIC_LEXER', 'BASIC_LEXER');
3 CTX_DDL.SET_ATTRIBUTE('TEST_BASIC_LEXER', 'MIXED_CASE', 'YES');
4 END;
5 /

PL/SQL 过程已成功完成。

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

索引已创建。

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

未选定行

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

ID
----------
4

如果不进行设置,Oracle在建立索引时会将所有的字母变为大写。如果进行了设置,可以使索引区分大小写

 

 

介绍完Oracle全文索引的BASIC_LEXER属性,这篇介绍Oracle中文语法属性CHINESE_LEXER和CHINESE_VGRAM_LEXER。

 

Oracle全文索引的BASIC属性主要是针对西方英语语系,英语语系的单词是通过空格、标点和回车来分隔的。而中文则需要索引来自动切词。
2 看下面这个例子:

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

表已创建。

SQL> INSERT INTO T VALUES (1, '一个中文例子,测试BASIC_LEXER语法属性是否可以正常识别中文。');

已创建 1 行。

SQL> COMMIT;

提交完成。

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

索引已创建。

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

未选定行

SQL> SELECT * FROM T WHERE CONTAINS(DOCS, '一个中文例子') > 0;

ID DOCS
---------- ------------------------------------------------------------
1 一个中文例子,测试BASIC_LEXER语法属性是否可以正常识别中文。

通过BASIC_LEXER来索引中文,Oracle只识别被空格、标点和回车符分隔出来的部分。需要对中文内容进行索引的话,就必须使用中文的LEXER。

Oracle提供了两种预定义的中文LEXER属性:CHINESE_VGRAM_LEXER和CHINESE_LEXER。Oracle在文档上是这样描述的:

CHINESE_LEXER相对应CHINESE_VGRAM_LEXER属性有如下的优点:

产生的索引更小;

更好的查询响应时间;

产生更接近真实的索引切词,使得查询精度更高;

支持停用词。

虽然Oracle说明了使用CHINESE_LEXER的大量好处,但是CHINESE_LEXER的实际效果却存在一定的问题:

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> TRUNCATE TABLE T;

表已截掉。

SQL> INSERT INTO T VALUES (1, '北京大学未名湖');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, '北京邮电大学');

已创建 1 行。

SQL> INSERT INTO T VALUES (3, '北京市第十四中学');

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> CONN CTXSYS/CTXSYS@YANGTK
已连接。
SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_CHINESE_VGRAM_LEXER', 'CHINESE_VGRAM_LEXER');
3 CTX_DDL.CREATE_PREFERENCE('TEST_CHINESE_LEXER', 'CHINESE_LEXER');
4 END;
5 /

PL/SQL 过程已成功完成。

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

索引已创建。

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

ID DOCS
---------- ------------------------------------------------------------
3 北京市第十四中学
2 北京邮电大学
1 北京大学未名湖

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

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

索引已创建。

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

ID DOCS
---------- ------------------------------------------------------------
2 北京邮电大学

通过对比结果可以发现:使用CHINESE_LEXER 没有将第一条记录和第三条记录中的北京检索出来。也许Oracle的CHINESE_LEXER认为北京大学和北京市是一个完整的词汇,而没有对其进行进 一步切分。也许这就是Oracle提到的这种切分方式更接近于真实的情况。我不知道读者会怎样看待这个问题,不过我更倾向于使用 CHINESE_VGRAM_LEXER,个人感觉返回记录多一些总比漏掉一些要好。

 

 

本文继续介绍Oracle 全文索引的LEXER 属性,这篇文章介绍Oracle 多语言全文索引DEFAULT_LEXER

要是DEFAULT_LEXER 其实并不复杂,但是确实最常使用的,无论是明确给出DEFAULT_LEXER 属性还是不指定LEXER 属性,Oracle 都会使用DEFAULT_LEXER 作为LEXER 的默认属性。

但是DEFAULT_LEXER 并不是一个真正意义上的LEXEROracle9i 的文档上描述的是,如果数据库在建立的时候指定的是中文则DEFAULT_LEXERCHINESE_VGRAM_LEXER ,如果是英文,则DEFAULT_LEXERBASIC_LEXER

但是我在很多Oracle9i 的环境下进行测试,发现无论按照时指定中文还是英文,DEFAULT_LEXER 的值都是BASIC_LEXER

SQL> CONN SYSTEM/MANAGER@DEMO2 已连接。
SQL> SELECT NAME, VALUE$ FROM SYS.PROPS$ WHERE NAME = 'NLS_LANGUAGE';

NAME VALUE$
---------------------------------------- --------------------
NLS_LANGUAGE SIMPLIFIED CHINESE

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

表已创建。

SQL> INSERT INTO T VALUES (1, ' 一个中文例子,测试默认的语法属性是否可以正常识别中文。');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, ' 根据Oracle 的文档,数据库的默认语言是中文会采用CHINA_VGRAM_LEXER');

已创建 1 行。

SQL> COMMIT;

提交完成。

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

索引已创建。

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

未选定行

SQL> SELECT PRE_NAME, PRE_OBJECT FROM CTX_PREFERENCES WHERE PRE_NAME = 'DEFAULT_LEXER';

PRE_NAME PRE_OBJECT
------------------------------ ------------------------------
DEFAULT_LEXER BASIC_LEXER

SQL> SELECT * FROM V$VERSION;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production

看来Oracle 的文档在这里的描述有问题,或者Oracle 的实现上和文档不一致。

但是测试发现Oracle10.2.0 中,如果按照的时候选择了中文,则DEFAULT_LEXER 属性的值为CHINESE_VGRAM_LEXER

SQL> CONN YANGTK/YANGTK@YTK 已连接。
SQL> SELECT NAME, VALUE$ FROM SYS.PROPS$ WHERE NAME = 'NLS_LANGUAGE';

NAME VALUE$
---------------------------------------- --------------------
NLS_LANGUAGE SIMPLIFIED CHINESE

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

表已创建。

SQL> INSERT INTO T VALUES (1, ' 一个中文例子,测试默认的语法属性是否可以正常识别中文。');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, ' 根据Oracle 的文档,数据库的默认语言是中文会采用CHINA_VGRAM_LEXER');

已创建 1 行。

SQL> COMMIT;

提交完成。

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

索引已创建。

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

ID DOCS
---------- ------------------------------------------------------------------
1
一个中文例子,测试默认的语法属性是否可以正常识别中文。
2
根据Oracle 的文档,数据库的默认语言是中文会采用CHINA_VGRAM_LEXER

SQL> SELECT PRE_NAME, PRE_OBJECT FROM CTX_PREFERENCES WHERE PRE_NAME = 'DEFAULT_LEXER';

PRE_NAME PRE_OBJECT
------------------------------ ------------------------------
DEFAULT_LEXER CHINESE_VGRAM_LEXER

SQL> SELECT * FROM V$VERSION;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

 

本文继续介绍Oracle全文索引的LEXER属性,这篇文章介绍Oracle多语言全文索引MULTI_LEXER。

如果在Oracle中存储多种语言,那么在建立全文索引的时候就不能只是简单的指定一个LEXER,而是要通过LANGUAGE COLUMN设置MULTI_LEXER。



下面看一个简单的例子:

SQL> CREATE TABLE T (ID NUMBER, LANGUAGE VARCHAR2(7), DOCS VARCHAR2(1000));

表已创建。

SQL> INSERT INTO T VALUES (1, 'english', 'This is a mixed language example.');

已创建 1 行。

SQL> INSERT INTO T VALUES (2, 'chinese', '中文信息应该使用中文语言属性CHINESE_VGRAM_LEXER进行索引');

已创建 1 行。

SQL> INSERT INTO T VALUES (3, 'chinese', '英文记录虽然可以通过中文语言属性CHINESE_VGRAM_LEXER继续索引');

已创建 1 行。

SQL> INSERT INTO T VALUES (4, '', 'But all the words is indexed by UPPER FORMAT.');

已创建 1 行。

SQL> COMMIT;

提交完成。

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

索引已创建。

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

未选定行

如果使用BASIC_LEXER作为LEXER属性的选项,那么就无法对中文使用索引。

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> CONN CTXSYS/CTXSYS@YANGTK
已连接。
SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_CHINESE_LEXER', 'CHINESE_VGRAM_LEXER');
3 END;
4 /

PL/SQL 过程已成功完成。

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

索引已创建。

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

ID LANGUAG DOCS
---------- ------- ----------------------------------------------------------
3 chinese 英文记录虽然可以通过中文语言属性CHINESE_VGRAM_LEXER继续索引
2 chinese 中文信息应该使用中文语言属性CHINESE_VGRAM_LEXER进行索引

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

ID LANGUAG DOCS
---------- ------- ---------------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

如果使用CHINESE_VGRAM_LEXER 属性的话,虽然可以对英文进行索引,但是中文LEXER无法进行属性的设置,如果想要对英文进行大小写敏感的查询,使用 CHINESE_VGRAM_LEXER属性是不行的,必须使用BASIC_LEXER,并进行MIXED_CASE属性设置。

SQL> DROP INDEX IND_T_DOCS;

索引已丢弃。

SQL> CONN CTXSYS/CTXSYS@YANGTK
已连接。
SQL> BEGIN
2 CTX_DDL.CREATE_PREFERENCE('TEST_ENGLISH', 'BASIC_LEXER');
3 CTX_DDL.SET_ATTRIBUTE('TEST_ENGLISH', 'MIXED_CASE', 'YES');
4 CTX_DDL.CREATE_PREFERENCE('TEST_CHINESE', 'CHINESE_LEXER');
5 CTX_DDL.CREATE_PREFERENCE('TEST_MULTI_LEXER', 'MULTI_LEXER');
6 CTX_DDL.ADD_SUB_LEXER('TEST_MULTI_LEXER', 'DEFAULT', 'TEST_ENGLISH');
7 CTX_DDL.ADD_SUB_LEXER('TEST_MULTI_LEXER', 'SIMPLIFIED CHINESE', 'TEST_CHINESE', 'CHINESE');
8 END;
9 /

PL/SQL 过程已成功完成。

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

索引已创建。

建立一个MULTI_LEXER 属性的索引,并通过LANGUAGE列设置需要索引的语言。Oracle会根据LANGUAGE列的内容去匹配ADD_SUB_LEXER过程中指定的语 言标识符。如果匹配的上,就使用该SUB_LEXER作为索引的LEXER,如果没有找到匹配的,就使用DEFAULT语言作为索引的LEXER列。

上面虽然建立了MULTI_LEXER索引,但是对多语言索引的查询却还存在一些额外的问题:

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

ID LANGUAG DOCS
---------- ------- ----------------------------------------------------------
3 chinese 英文记录虽然可以通过中文语言属性CHINESE_VGRAM_LEXER继续索引
2 chinese 中文信息应该使用中文语言属性CHINESE_VGRAM_LEXER进行索引

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

未选定行

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

未选定行

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

ID LANGUAG DOCS
---------- ------- ------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

通过上面的查询结果可以推测出,BASIC_LEXER并没有起作用。对于中文的查询可以生效,但是对于字符大小写敏感的查询都不会生效。可以生效的查询只是原文中就使用大写的单词。

这是由于当前客户端的语言设置是简体中文,这和索引中的一个SUB_LEXER相匹配,因此Oracle选择了该LEXER的索引结果作为查询的返回结果。下面将NLS_LANGUAGE设置为英文:

SQL> SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER = 'NLS_LANGUAGE';

PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE SIMPLIFIED CHINESE

SQL> ALTER SESSION SET NLS_LANGUAGE = 'AMERICAN';

Session altered.

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

ID LANGUAG DOCS
---------- ------- -----------------------------------------------------------
3 chinese 英文记录虽然可以通过中文语言属性CHINESE_VGRAM_LEXER继续索引
2 chinese 中文信息应该使用中文语言属性CHINESE_VGRAM_LEXER进行索引

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

no rows selected

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

ID LANGUAG DOCS
---------- ------- --------------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

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

ID LANGUAG DOCS
---------- ------- --------------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

结果恢复了正常,如果将语言不设置为DEFAULT LEXER,而是设置索引包含的LEXER以外的语言,查询也是正常的。

SQL> ALTER SESSION SET NLS_LANGUAGE = 'TRADITIONAL CHINESE';

Session altered.

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

ID LANGUAG DOCS
---------- ------- -----------------------------------------------------------
3 chinese 英文记录虽然可以通过中文语言属性CHINESE_VGRAM_LEXER继续索引
2 chinese 中文信息应该使用中文语言属性CHINESE_VGRAM_LEXER进行索引

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

no rows selected

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

ID LANGUAG DOCS
---------- ------- -----------------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

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

ID LANGUAG DOCS
---------- ------- -----------------------------------------------------------
4 But all the words is indexed by UPPER FORMAT.

这就是说,对于包含多种语言的全文索引需要额外的小心。尤其是客户端的语言设置与全文索引中的非DEFAULT属性的SUB_LEXER的语言一致的情况。这个时候查询语句会仅返回当前语言下的索引记录。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值