暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

达梦 全文索引

原创 行之 2025-01-19
1211

达梦 全文索引

  • 全文索引必须在基表上定义,而不能在系统表、视图、临时表、列存储表、外部表上定义。

  • 同一列只能创建一个全文索引

  • 全文索引列的类型可为 CHAR、CHARACTER、VARCHAR、VARCHAR2、LONGVARCHAR、TEXT 或 CLOB

  • 全文索引现只支持简体中文、英文语言

  • 基表数据变化,需更新全文索引。

  • 创建全文索引会新增四个辅助表,辅助表在user_tables视图下看不到,但能直接查询数据。如索引名INDEX_NAME,则四个辅助表为:

    • CTI$INDEX_NAME$I,用于保存分词结果,I表会比较大。

    • CTI$INDEX_NAME$P,用于保存基表发生数据变化的ROWID及操作类型,及用户自定义聚集索引

    • CTI$INDEX_NAME$N,用于保存基表ROWID和分词docid 的映射关系,及用户自定义聚集索引

    • CTI$INDEX_NAME$D,记录将被删除的 docid

一 创建全文索引

CREATE CONTEXT INDEX cti_address ON person.address (address1) LEXER DEFAULT_LEXER SYNC [TRANSACTION];
-- SYNC 子句为可选参数,默认创建全文索引不会更新分词数据,全文索引创建后不可直接使用。
-- SYNC参数,在创建全文索引时执行一次全量更新,创建后即可使用全文检索
-- SYNC TRANSACTION 参数,在创建全文索引时执行一次全量更新,且每次事务提交都增量更新全文索引。

关键字 LEXER 指定分词算法:

  1. CHINESE_LEXER,中文最少分词,

  2. CHINESE_VGRAM_LEXER,中文机械双字分词;

  3. CHINESE_FP_LEXER,中文最多分词,中文场景只有这个能用,推荐 !!!

  4. ENGLISH_LEXER,英文分词;

  5. DEFAULT_LEXER,默认分词,为中文最少分词。

其中,中文分词可以切分英文,英文分词不能切分中文,所以中英混合列推荐中文分词。

中文分词依赖系统词库,该词库是只读的,不允许修改。

二 删除全文索引

DROP CONTEXT INDEX cti_address ON person.address;

三 更新全文索引

全文索引本质是借助辅助表存储索引数据。基表数据发生变化,需要用户主动同步数据以更新全文索引,或设置服务器自动更新

全文索引的更新包括两种方式:完全更新和增量更新。

  1. 判断是否需要更新

    select count(1) from CTI$CTI_ADDRESS$I; -- 记录数大于0,说明已有分词信息。
    SELECT COUNT(1) FROM CTI$CTI_ADDRESS$P; -- 记录数大于0,说明有数据更新,需要更新分词信息,更新后会重新变为0.
    -- CTI_ADDRESS 替换为自己创建的全文索引名
  2. 完全更新

      ALTER CONTEXT INDEX cti_address ON person.address REBUILD;
    • 完全更新会删除原有全文索引,重新扫描索引列并分词,代价较大,耗时较久。

    • 完全更新可以修改分词算法;

    • 增量更新失败可考虑完全更新。

  3. 增量更新,推荐!!!

      ALTER CONTEXT INDEX cti_address ON person.address INCREMENT;
    • 增量更新只对新发生改变的数据进行重新分词并生成索引信息,代价较小,耗时较短。

    • 增量更新失败,会回滚到之前的状态。

    DMDSC 环境下更新全文索引前,需要手动将 dmdbms/bin/SYSWORD.UTF8.LIB 文件复制到库所在的 DMASM 路径下,否则会导致全文索引词库加载错误。

四 进行全文检索

如:
SELECT * FROM person.address WHERE CONTAINS(address1, '江汉区发展大道');
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区' AND '太阳城');
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区' OR '太阳城');
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区' AND NOT '太阳城');
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区') AND city LIKE '%武汉市%';

五 测试验证

1.创建测试表

create user cym identified by "Test_1234";
grant resource,public,soi,svi to cym;
conn cym/Test_1234
create table fulltext (id int IDENTITY(1,1) cluster primary key,name varchar(20),birth datetime(0),address varchar(100));

使用SQLark 生成 10w条数据

2.创建全文索引

drop context index cti_address on fulltext; -- 删除全文索引
CREATE CONTEXT INDEX cti_address ON fulltext (address) LEXER DEFAULT_LEXER;

3.检查

SQL> select table_name from user_tables;  -- user_tables 没看到辅助表
TABLE_NAME
----------
FULLTEXT
SQL> select * from ctisys.syscontextindexes;    -- ctisys.syscontextindexes 能查到已有的全文索引,其中 WSEG_TYPE 表示分词算法
NAME        ID          TABLEID     COLID       UPD_TIMESTAMP              TIID        TDID        TPID        TNID        TRID        WSEG_TYPE   RESVD
----------- ----------- ----------- ----------- -------------------------- ----------- ----------- ----------- ----------- ----------- ----------- ----------
CTI_ADDRESS 33555530    1068        3           2025-01-19 17:25:10.586854 1073        1075        1074        1076        NULL        0           NULL

SQL> select table_name,index_name,index_type,status from user_indexes order by table_name;  -- user_indexes 看到已有辅助表,全文索引类型为domain
TABLE_NAME        INDEX_NAME        INDEX_TYPE STATUS
----------------- ----------------- ---------- ------
CTI$CTI_ADDRESS$D INDEX33555533     CLUSTER    VALID
CTI$CTI_ADDRESS$I INDEX33555531     CLUSTER    VALID
CTI$CTI_ADDRESS$N INDEX33555534     CLUSTER    VALID
CTI$CTI_ADDRESS$N IDX$CTI_ADDRESS$N NORMAL     VALID
CTI$CTI_ADDRESS$P INDEX33555532     CLUSTER    VALID
FULLTEXT          CTI_ADDRESS       DOMAIN     VALID
FULLTEXT          INDEX33555523     CLUSTER    VALID

SQL> select count(1) from CTI$CTI_ADDRESS$I;    -- 分词信息,0条
COUNT(1)
--------------------
0

SQL> select * from fulltext where contains(address,'张家界');  -- 创建全文索引不能直接使用,需先填充。
未选定行
已用时间: 1.117(毫秒). 执行号:58810.


4.更新全文索引并检索

------------- 1.全量更新分词信息 -------------------
SQL> ALTER CONTEXT INDEX cti_address ON fulltext REBUILD;
SQL> select count(1) from CTI$CTI_ADDRESS$I;
COUNT(1)
--------------------
17034              -- 已经有分词信息

-------------- 2.进行全文检索 ---------------------
SQL> select COUNT(1) from fulltext where address LIKE '%张家界%';
COUNT(1)
--------------------
194
已用时间: 26.986(毫秒). 执行号:58839.     --作为对比,关键字匹配到 194条记录,耗时27ms

SQL> select * from fulltext where contains(address,'张家界');
未选定行
SQL> select * from fulltext where contains(address,'张家');   
ID          NAME   BIRTH                      ADDRESS
----------- ------ -------------------------- ------------------------------
8632        周曼婷 2013-08-01 05:36:43.000000 山东省淄博市张店区洪家楼6418567       柴诗涵 2003-11-24 06:02:11.000000 湖北省宜昌市伍家岗区张庄路7781334       汪智瑄 2018-11-17 17:50:32.000000 山东省淄博市张店区姚家76号

SQL> select * from fulltext where contains(address,'山东'); 
未选定行

默认分词算法完全不能用!!!

5.更换分词算法为最多分词

SQL> drop context index cti_address on fulltext;
SQL> CREATE CONTEXT INDEX cti_address ON fulltext (address) LEXER CHINESE_FP_LEXER SYNC; -- 创建全文索引的同时,更新分词信息。
SQL> select count(1) from CTI$CTI_ADDRESS$I;
COUNT(1)
--------------------
31196
SQL> select * from fulltext where contains(address,'张家界');
ID          NAME   BIRTH                      ADDRESS
----------- ------ -------------------------- --------------------------------
1           项欣怡 2015-06-17 16:26:43.000000 湖南省张家界市慈利县舜耕61546         甄向欢 1977-12-16 14:48:48.000000 湖南省张家界市慈利县中大槐树15916         胡永   2011-08-19 10:51:45.000000 湖南省张家界市永定区遥墙631091        尹麟超 2015-12-22 08:23:43.000000 湖南省张家界市武陵源区七里山87号
...
194 rows got

SQL> select COUNT(1) from fulltext where contains(address,'张家界');
COUNT(1)
--------------------
194
已用时间: 2.228(毫秒). 执行号:58838.         -- 194条数据,检索结果符合预期。

SQL> select count(1) from fulltext where contains(address,'张家界' AND '大槐树');
COUNT(1)
--------------------
3
已用时间: 14.396(毫秒). 执行号:58844.

SQL> select count(1) from fulltext where contains(address,'张家界' AND NOT '大槐树');
COUNT(1)
--------------------
191     -- 这两个AND 和 AND NOT 之和是194,符合预期。
已用时间: 13.782(毫秒). 执行号:58845.


最多分词算法效果完美,效率比模糊匹配也快很多, 但注意条件越多耗时越久。

6.记录删除

SQL> select count(1) from fulltext where contains(address,'四川省');   --2897
SQL> DELETE FROM fulltext WHERE contains(address,'四川省');
影响行数 2897
SQL> select count(1) from fulltext where contains(address,'四川省');
COUNT(1)
--------------------
0

记录删除操作不需要更新全文索引。

7.记录新增

SQL> INSERT INTO fulltext(name,birth,address) VALUES('陈年酒诗',now(),'陈年酒诗');
SQL> INSERT INTO fulltext(name,birth,address) VALUES('陈年酒诗',now(),'陈年酒诗');
SQL> SELECT COUNT(1) FROM CTI$CTI_ADDRESS$P;                -- 2
SQL> SELECT * FROM FULLTEXT WHERE CONTAINS(ADDRESS,'陈年');  -- 0
SQL> ALTER CONTEXT INDEX ON FULLTEXT INCREMENT;             -- 增量刷新
SQL> SELECT * FROM FULLTEXT WHERE CONTAINS(ADDRESS,'陈年');
ID          NAME     BIRTH                      ADDRESS
----------- -------- -------------------------- --------
100002      陈年酒诗 2025-01-19 19:33:03.341247 陈年酒诗
100003      陈年酒诗 2025-01-19 19:41:11.213052 陈年酒诗

已用时间: 0.447(毫秒). 执行号:82614.
SQL> SELECT * FROM FULLTEXT WHERE ID IN (100002,100003);
ID          NAME     BIRTH                      ADDRESS
----------- -------- -------------------------- --------
100002      陈年酒诗 2025-01-19 19:33:03.341247 陈年酒诗
100003      陈年酒诗 2025-01-19 19:41:11.213052 陈年酒诗

已用时间: 0.366(毫秒). 执行号:82615.

记录新增需要更新全文索引。

8.占用空间对比

SQL> SELECT USER_USED_SPACE('CYM');
行号     USER_USED_SPACE('CYM')
---------- -----------------------
1          1120

SQL> DROP CONTEXT INDEX CTI_ADDRESS ON CYM.FULLTEXT;
操作已执行

SQL> SELECT USER_USED_SPACE('CYM');
行号     USER_USED_SPACE('CYM')
---------- -----------------------
1          256

全文索引占用空间较大,是一种以空间换时间的SQL优化方案。

参考

  1. 全文检索:https://eco.dameng.com/document/dm/zh-cn/pm/full-text-search.html

  2. 管理全文索引:https://eco.dameng.com/document/dm/zh-cn/pm/definition-statement#3.8%20%E7%AE%A1%E7%90%86%E5%85%A8%E6%96%87%E7%B4%A2%E5%BC%95

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论