现有的数据库系统,绝大多数是以结构化数据为检索的主要目标,因此实现相对简单。比如数值检索,可以建立一张排序好的索引表,这样速度可以得到提高。但对于非结构化数据,即全文数据,要想实现检索,一般都是采用模糊查询的方式实现的。这种方式不仅速度慢,而且容易将汉字错误切分,于是产生了全文检索技术。
全文检索技术是智能信息管理的关键技术之一,其主要目的就是实现对大容量的非结构化数据的快速查找。DM 实现了全文检索功能,并将其作为 DM 服务器的一个较独立的组件,提供更加准确的全文检索功能,较好地解决了模糊查询方式带来的问题。
18.1 全文检索概述
DM 全文检索根据已有词库建立全文索引,文本查询完全在索引上进行。全文索引为在字符串数据中进行复杂的词搜索提供了有效支持。
用户可以在指定表的文本列上创建和删除全文索引。创建全文索引后全文索引未插入任何索引信息。当用户填充全文索引时,系统才将定义了全文索引的文本列的内容进行分词,并根据分词结果填充索引。用户可以在进行全文索引填充的列上使用 CONTAINS 谓词进行全文检索。
DM 全文索引改进了原有的分词算法,为全文检索提供了更好的基础。在创建全文索引成功后,假设索引名为 INDEX_NAME,则系统会自动产生如下相关的辅助表(后面简称 I 表,P 表,N 表,D 表):CTI$INDEX_NAME$I,CTI$INDEX_NAME$P, CTI$INDEX_NAME$N 和 CTI$INDEX_NAME$D,其表结构如表 18.1~18.4 所示。I 表主键为(WORD、FIRSTID、WID),用于保存分词结果,记录词的基本信息,通过该信息就可以快速地定位到该词的基表记录;P 表主键为(PND_DOCID),用于保存基表发生的增量数据变化,用于修改全文索引时的增量填充。N 表主键为(N_DOCID),用于保存原表记录 rowid 和新词条记录的 docid 的映射关系,N_DOCID 是 unique 的;D 表主键为(DOCID),保存了所有将被删除的 docid,被删除的 docid 即将不能通过全文索引查询到。另外,如果原表有自定义聚集主键,那么 P 表和 N 表会将该自定义聚集主键列“复制”到各自表中。
序号 | 字段名 | 类型 | 长度 | 精度 | 刻度 | 说明 |
---|---|---|---|---|---|---|
1 | WID | BIGINT | 8 | 19 | 0 | 词 ID |
2 | WORD | VARCHAR | 64 | 64 | 0 | 词文本,相同的词重复存储 |
3 | TYPE | SMALLINT | 2 | 5 | 0 | 词类型 |
4 | FIRSTID | ROWID | 8 | 19 | 0 | 开始 ROWID,用于范围查找 |
5 | LASTID | ROWID | 8 | 19 | 0 | 结束 ROWID |
6 | COUNT | INTEGER | 4 | 10 | 0 | 词所在的文档数(即 ROWID 的个数) |
7 | ID_INFO | VARBINARY | 4000 | 4000 | 0 | 保存所在文档所有的 ROWID,连续存放 |
序号 | 字段名 | 类型 | 长度 | 精度 | 刻度 | 说明 |
---|---|---|---|---|---|---|
1 | PND_ROWID | ROWID | 8 | 19 | 0 | 原表记录的 ROWID |
2 | PND_TYPE | SMALLINT | 2 | 5 | 0 | INS/UPD/DEL 类型 |
cluster key | ... | ... | ... | ... | 原表上的自定义聚集主键 |
序号 | 字段名 | 类型 | 长度 | 精度 | 刻度 | 说明 |
---|---|---|---|---|---|---|
1 | N_DOCID | ROWID | 8 | 19 | 0 | 与原表 ROWID |
2 | N_ROWID | ROWID | 8 | 19 | 0 | 原表记录 ROWID |
cluster key | ... | ... | ... | ... | 原表上的自定义聚集主键 |
序号 | 字段名 | 类型 | 长度 | 精度 | 刻度 | 说明 |
---|---|---|---|---|---|---|
1 | DOCID | ROWID | 8 | 19 | 0 | 待删除词的 DOCID |
例 对示例库 bookshop 中的 address 表的 address1 列创建全文索引,创建的 SQL 语句如下:
CREATE CONTEXT INDEX cti_address ON person.address (address1) LEXER DEFAULT_LEXER;
执行成功之后,该索引信息会保存到 ctisys 模式下的 SYSCONTEXTINDEXES 系统表中,4 个自动生成的辅助表 CTI$ CTI_ADDRESS$I,CTI$ CTI_ADDRESS$P, CTI$ CTI_ADDRESS$N 和 CTI$ CTI_ADDRESS$D 信息保存在 SYSOBJECTS 系统表中。这四张表由服务器自动维护,用户可以查询,但不可以直接修改表内容。
DM 全文索引创建的过程中,用户可以为分词器定义分词参数,即控制分词器分词的数量,包括 5 种分词参数:
- CHINESE_LEXER,中文最少分词;
- CHINESE_VGRAM_LEXER,机械双字分词;
- CHINESE_FP_LEXER,中文最多分词;
- ENGLISH_LEXER,英文分词;
- DEFAULT_LEXER,默认分词,为中文最少分词。
指定中文分词参数可以切分英文,但是指定英文分词参数不可以切分中文,所以使用英文分词算法对中文文本进行分词时,分词结果将为空。
中文最多分词可以将存在二义性的词划分出来,例如:“和服装”会生成“和”、“和服”、“服”、“服装”和“装”。那么在查询其中任何一个词的时候都可以检索到该文本。与之相对应的是最少分词,其消除了存在二义性的词,即前面举例的文本分词的结果为“和”、“服装”两个词,这样可以减少大量冗余词的存储,能进行更准确的匹配。英文分词即根据英文分隔符的分词,对超过 32 个字节的英文单词进行了拆分处理。
全文检索的中文分词依赖系统词库,该词库是只读的,不允许修改。
18.2 创建全文索引
在 DM 中,全文索引必须在基表上定义,而不能在系统表、视图、临时表、列存储表、外部表上定义。同一列只能创建一个全文索引。DM 定义全文索引时,不需要在表上先建立主关键字索引。创建全文索引的列类型可为 CHAR、CHARACTER、VARCHAR、VARCHAR2、LONGVARCHAR、TEXT 或 CLOB,例如上节对 address 表创建的全文索引列为 VARCHAR 类型。DM 的全文索引现只支持简体中文、英文语言。较为详细的语法介绍可参考《DM8_SQL 语言使用手册》。
18.3 更新全文索引
全文索引本质是借助辅助关系表存储索引数据。当对基表执行数据更新操作后,数据并不会立刻填充到辅助表中,需要用户主动同步数据用以更新全文索引,未同步到辅助表中的记录将无法通过全文索引查询到结果。
全文索引的更新包括两种方式:完全更新和增量更新。
- 完全更新
删除原有的全文索引,对基表进行全表扫描,逐一重构索引信息。在创建全文索引成功后,需完完全更新全文索引才可以执行有效的全文检索。完全更新全文索引没有次数限制,用户可以根据需要在增量更新或者是完全更新失败以及发生系统故障后都可以执行完全更新全文索引。另外,完全更新由于完全丢弃辅助表已有数据,重新开始对基表数据进行分词并填充到辅助表,因此服务器允许这种情况下更改分词算法。
例 执行如下 SQL 可以对 address 表的全文索引进行完全更新
ALTER CONTEXT INDEX cti_address ON person.address REBUILD;
- 增量更新
在上一次完全更新之后,表数据发生了变化,就可以使用增量更新来更新索引。增量更新只对新发生改变的数据进行重新分词生成索引信息,所以其代价是较小的。此时,也可以使用完全更新达到同样的更新索引的效果,但代价较大。
对全文索引的基表进行数据的增删改操作时,会将该数据的操作类型和 ROWID 信息保存到 CTI$INDEX_NAME$P 表中。
例 执行如下 SQL 可以对 address 表的全文索引进行增量更新
ALTER CONTEXT INDEX cti_address ON person.address INCREMENT;
DM 在执行更新全文索引的过程中如果在更新过程中发生任何错误,服务器将回滚到最近一次事务提交成功时的状态。
无论是完全更新还是增量更新,在 DMDSC 环境下更新全文索引前,需要手动将执行码目录下的 SYSWORD.UTF8.LIB 文件复制到库所在的 DMASM 路径下,否则会导致全文索引词库加载错误。
增量更新还有一种特殊情况,实时自动增量更新,即在创建全文索引时指定同步方式为"SYNC TRANSACTION",此种方式不需要用户手动更新全文索引,而是在每次事务提交时由服务器自动完成增量更新动作。
18.4 执行全文检索
全文检索采用的分词算法与全文索引数据同步时采用的分词算法保持一致,用户可以通过系统表"CTISYS.SYSCONTEXTINDEXES"查询"WSEG_TYPE"得知全文索引的分词算法。全文检索首先对查询关键字或者句子进行分词,并将分词结果在 I 表中进行匹配,然后将匹配结果返回。DM8 支持对中英文关键字或者句子的布尔查询。
全文检索支持的检索类型有:
- 支持英文单词的检索(单词不区分大小写);
- 支持全角英文的检索;
- 支持简体中文词语的检索;
- 支持常见单个汉字词的检索;
- 支持简体中文长句子的检索;
- 支持中英文混合的检索。
全文检索支持的检索方式有:
-
在 CONTAINS 谓词内支持 AND、OR 和 AND NOT 的短语查询组合条件。
例 查询 address 表中地址在洪山区太阳城的记录:
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区' AND '太阳城');
-
全文检索支持单词或者句子的检索。
例 查询 address 表中地址在江汉区发展大道的记录:
SELECT * FROM person.address WHERE CONTAINS(address1, '江汉区发展大道');
- 不支持模糊方式的全文检索,例如查询“江汉区*”。
- 检索条件子句可以和其他子句共同组成 WHERE 的检索条件,例如查询 address 表中地址在武汉市洪山区的记录。
SELECT * FROM person.address WHERE CONTAINS(address1, '洪山区') AND city LIKE '%武汉市%';
如上图所示,DM 全文检索时对查询的文本做了预处理,首先根据词文本进行最少分词,并依据词频信息找出查询关键字,然后对这些关键字进行优先级排序,这样可以在第一次检索时找出所需文本的最小结果集,然后在该结果集的基础上再进行依次筛选,最终获得查询文本,这样能较大地提高查询性能。
18.5 删除全文索引
删除全文索引时,数据字典中相应的索引信息和全文索引内容都会被删除。删除索引有两种方式:使用语句删除和当模式对象发生改变时系统自动删除。第一种方式仅删除指定的基表的全文索引信息;第二种方式会删除模式对象(如数据库、基表等)上的所有全文索引。全文索引一旦删除就不能回滚,基于该表的全文检索就会失败,只能通过重新构建获得新的全文索引。
例 删除 address 表,则会将表的全文索引 cti_address 也删除,包括与全文索引相关的动态表
DROP CONTEXT INDEX cti_address ON person.address;
删除成功后,查询 ctisys 模式下的 SYSCONTEXTINDEXES 系统表会发现 cti_address 全文索引已删除。