本文继续介绍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的语言一致的情况。这个时候查询语句会仅返回当前语言下的索引记录。