联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
日常开发中,我们经常需要检索文章、评论、新闻、商品描述等大段文本内容。
如果还在使用LIKE %关键词%模糊查询,不仅无法命中语义、无法按相关性排序,数据量大时还会出现查询性能暴跌的问题。
针对海量文本检索场景,OceanBase 提供了**全文索引(Fulltext Index)**能力,搭配多类型分词器、两种查询模式,完美适配中英文文本搜索,是业务文本检索的最优解决方案。
今天这篇干货,带你吃透 OceanBase 全文索引:核心概念、使用限制、分词器的基础概念和语法。
全文索引(Fulltext Index)是一种专门用于对文本内容(如 CHAR、VARCHAR、TEXT 类型的列)进行高效、灵活搜索的数据库索引。
全文索引通过分词器将大段文本拆分成一个个有意义的“词元”(token),然后基于这些词元建立索引。这使得你可以进行关键词搜索、模糊匹配等复杂的文本查询。让你能在海量文本数据中,快速查找到包含特定单词或短语的记录。
创建语法
CREATE TABLE table_name(column_name column_definition,[column_name column_definition,...]
FULLTEXT [INDEX | KEY] [index_name](column_name)
[WITH PARSER tokenizer_option]
[PARSER_PROPERTIES[=](parser_properties_list)]
[LOCAL]);
tokenizer_option:
SPACE
| NGRAM
| BENG
| IK
| NGRAM2
parser_properties_list:
parser_properties, [parser_properties]
parser_properties:
min_token_size = int_value
| max_token_size = int_value
| ngram_token_size = int_value
| ik_mode = 'char_value'
| min_ngram_size = int_value
| max_ngram_size = int_value
-- OB版本4353
obclient [test] select version();
+------------------------------+
| version() |
+------------------------------+
| 5.7.25-OceanBase_CE-v4.3.5.3 |
+------------------------------+
1 row in set (0.001 sec)
-- 建表时创建 默认space分词器
obclient [test] CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(200),
content TEXT,
FULLTEXT INDEX ft_idx (title, content)
);
Query OK, 0 rows affected (0.253 sec)
-- 查看索引
obclient [test] show index from articles;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| articles | 0 | PRIMARY | 1 | id | A | NULL | NULL | NULL | | BTREE | available | | YES | NULL |
| articles | 1 | ft_idx | 1 | title | A | NULL | NULL | NULL | YES | FULLTEXT | available | | YES | NULL |
| articles | 1 | ft_idx | 2 | content | A | NULL | NULL | NULL | YES | FULLTEXT | available | | YES | NULL |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
3 rows in set (0.004 sec)
-- 删除索引
obclient [test] alter table articles drop index ft_idx;
Query OK, 0 rows affected (1.034 sec)
-- 为已有的表添加全文索引,并且指定分词器
obclient [test] ALTER TABLE articles ADD FULLTEXT INDEX ft_idx_ik (content) WITH PARSER IK;
Query OK, 0 rows affected (0.950 sec)
-- 查看索引
obclient [test] show index from articles;
+----------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+----------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| articles | 0 | PRIMARY | 1 | id | A | NULL | NULL | NULL | | BTREE | available | | YES | NULL |
| articles | 1 | ft_idx_ik | 1 | content | A | NULL | NULL | NULL | YES | FULLTEXT | available | | YES | NULL |
+----------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
2 rows in set (0.002 sec)
分词器(Tokenizer)是全文索引的核心引擎,它决定了如何将一段文本拆解成可供搜索的最小单元(词元)。
分词器列表:
以空格、标点符号(如逗号、句号)或非字母数字字符(除下划线 _ 外)为分隔符拆分文本。
分词结果仅包含长度在 min_token_size(默认 3)到 max_token_size(默认 84)之间的有效词元。
中文字符被视为单个字符处理。
obclient [test] select tokenize('Root_service ensures balanced distribution of partition counts and disk usage across all nodes. ','SPACE') as space_token;
+----------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+----------------------------------------------------------------------------------------------------------------------------------+
| ["nodes", "all", "across", "usage", "disk", "and", "counts", "partition", "distribution", "balanced", "ensures", "root_service"] |
+----------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
与 Space 分词器类似,但不保留下划线 _,将其视为分隔符。
适用于英文短语分隔,但对无空格术语(如 “iPhone15”)切分效果有限。
obclient [test] select tokenize('Root_service ensures balanced distribution of partition counts and disk usage across all nodes. ','beng') as space_token;
+-------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+-------------------------------------------------------------------------------------------------------------------------------------+
| ["nodes", "all", "across", "usage", "disk", "and", "counts", "partition", "distribution", "balanced", "ensures", "service", "root"] |
+-------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
基于开源工具 IK Analyzer 的中文分词器,支持两种模式:
Smart 模式:优先输出长词,减少切分数量 (如“南京市”不切分为“南京”“市”)。
Max Word 模式:输出所有可能的短词(如“南京市”切分为“南京”“市”)。
自动识别英文单词、邮箱、URL(不含 ://)、IP 地址等格式。
-- smart模式
obclient [test] select tokenize('全文索引通过分词器将大段文本拆分成一个个有意义的“词元”(token),然后基于这些词元建立索引。','IK','[{"additional_args":[{"ik_mode": "smart"}]}]') as space_token;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["索引", "建立", "这些", "基于", "然后", "token", "元", "词", "的", "有意义", "一个个", "分成", "拆", "文本", "大段", "将", "分词器", "通过", "全文索引"] |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
-- max_word模式
obclient [test] select tokenize('全文索引通过分词器将大段文本拆分成一个个有意义的“词元”(token),然后基于这些词元建立索引。','IK','[{"additional_args":[{"ik_mode": "max_word"}]}]') as space_token;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["建立", "这些", "基于", "然后", "token", "元", "词", "的", "意义", "有意", "有意义", "个", "个个", "一", "一个", "一个个", "分成", "拆分", "文本", "大段", "将", "器", "分词", "分词器", "过分", "通过", "索引", "全文", "全文索引"] |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
固定n值分词:默认 n=2,将连续非分隔符字符拆分为长度为 n 的子序列。
分隔符判定规则同 Space 分词器(保留 _ 和数字字母)。
不支持长度限制参数,输出所有可能的 n 长度词元。
select tokenize('全文索引','NGRAM') as space_token;
+--------------------------------+
| space_token |
+--------------------------------+
| ["索引", "文索", "全文"] |
+--------------------------------+
1 row in set (0.000 sec)
obclient [test] select tokenize('全文索引通过分词器将大段文本拆分成一个个有意义的“词元”(token),然后基于这些词元建立索引。','NGRAM') as space_token;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["立索", "建立", "元建", "些词", "这些", "于这", "基于", "后基", "然后", "en", "ke", "ok", "to", "词元", "义的", "意义", "有意", "个有", "个个", "一个", "成一", "分成", "拆分", "本拆", "文本", "段文", "大段", "将大", "器将", "词器", "分词", "过分", "通过", "引通", "索引", "文索", "全文"] |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
| 分词器 | 主要特点 | 适应场景 |
|---|---|---|
| Space 分词器 (默认) | 以空格、标点分隔(除了下划线_) | 英文等以空格分隔的语言。 |
| IK 分词器 | 专为中文设计,支持smart和max_word(全切分)模式,能识别邮箱、URL等。 | 中文文本搜索,如商品描述、评论分析。 |
| Ngram 分词器 | 按固定长度(如2个字符)机械切分,不依赖词典。 | 短文本模糊匹配,如产品型号、用户ID。 |
| Ngram2 分词器 | 支持动态长度范围切分,但内存消耗可能较高。 | 需要同时匹配多种长度词元的场景。 |
全文查询是指在文本数据中进行全文搜索或检索的操作。它用于查找包含特定关键词、短语或文本表达式的文本内容。全文查询能够更全面地搜索整个文本,并返回与搜索条件匹配的结果。
MATCH (column_name [, column_name ...]) AGAINST (expr [search_modifier])
search_modifier:
IN NATURAL LANGUAGE MODE
| IN BOOLEAN MODE
IN NATURAL LANGUAGE MODE:默认值,用于指定使用自然语言搜索模式进行搜索。该模式的全文搜索是通过对查询表达式(query_expr)进行分词得到词条(token)集合,与索引中的词条(token)进行匹配来进行检索,只要有一个词条与查询表达式中的词条匹配成功就视为匹配成功。同时会通过基于词频的方法(Okapi BM25)对被匹配成功的行相关性进行 ranking(排序)。
默认情况下或者指定 IN NATURAL LANGUAGE MODE 标示符,MATCH AGAINST 将使用 NATURAL LANGUAGE 模式来进行全文查找。在 NATURAL LANGUAGE 模式下,AGAINST 接受一个查找字符串,并且按照字符集的比较方式在索引中进行查找,对于表中的每一行数据,MATCH 的返回值代表了查找字符串和行中数据的相关度,也就是查找字符串中的文本和数据表中的文本相似度。
IN BOOLEAN MODE:用于指定使用布尔模式进行搜索。当前版本支持三种最常用的布尔运算符,以及运算嵌套,具体如下:
+:表示 AND,交集。
-:表示非,差集。
无操作符号:单独使用时表示 OR,并集,如 A B 表示 A OR B。和符号混用会让存在的句子相关性变高,但会失去 OR 的语意,如 +A B 时,表示必须有 A,并计算句子中 A 和 B 的相关性。
():表示运算嵌套。外层无符号时,有 OR 的语意,如 +A (嵌套子句),表示必须有 A 或者有嵌套子句。
obclient [test] CREATE TABLE news_articles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL COMMENT '新闻标题',
-- 使用TEXT类型存储新闻正文,这是全文索引的主要目标列
content TEXT NOT NULL COMMENT '新闻正文',
publish_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间',
-- 为content列创建全文索引,使用IK分词器(假设已安装支持)
-- 关键:FULLTEXT INDEX 和 WITH PARSER 子句
FULLTEXT INDEX ft_idx_content (content) WITH PARSER IK
) COMMENT='新闻测试表' CHARSET=utf8mb4;
Query OK, 0 rows affected (0.264 sec)
obclient [test] desc news_articles;
+--------------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+-------------------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| title | varchar(200) | NO | | NULL | |
| content | text | NO | | NULL | |
| publish_time | datetime | YES | | CURRENT_TIMESTAMP | |
+--------------+--------------+------+-----+-------------------+----------------+
4 rows in set (0.002 sec)
obclient [test] show index from news_articles;
+---------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+---------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
| news_articles | 0 | PRIMARY | 1 | id | A | NULL | NULL | NULL | | BTREE | available | | YES | NULL |
| news_articles | 1 | ft_idx_content | 1 | content | A | NULL | NULL | NULL | | FULLTEXT | available | | YES | NULL |
+---------------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+------------+
2 rows in set (0.004 sec)
obclient [test] INSERT INTO news_articles (title, content) VALUES
-- 文档A:高度相关,两个关键词都出现且“小明”多次出现
('小明获奖', '来自西安市的优秀学生小明,在近日的全国竞赛中,小明以其出色的表现获得了一等奖。小明的导师表示,这是西安市的骄傲。'),
-- 文档B:相关,但关键词出现次数少,文档更长(稀释了密度)
('城市新闻', '西安市今日举行了一场大型环保活动。志愿者小明与数百位市民一同参与了清洁工作。本次活动旨在提升市民的环保意识,建设更美丽的西安市。相关部门表示未来将持续举办此类活动。'),
-- 文档C:只包含一个关键词
('古城动态', '西安市作为历史文化名城,近年来在城市规划和旅游发展方面取得了显著成就。'),
-- 文档D:包含“小明”但不包含“西安市”
('个人事迹', '热心市民小明多年来坚持社区志愿服务,他的事迹被广泛报道。'),
-- 文档E:包含同义词但无精确关键词
('都市故事', '在某个北方大都市,一位名叫张伟的年轻人也取得了类似的成就。');
Query OK, 5 rows affected (0.371 sec)
Records: 5 Duplicates: 0 Warnings: 0
obclient [test] select * from news_articles;
+----+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
| id | title | content | publish_time |
+----+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
| 1 | 小明获奖 | 来自西安市的优秀学生小明,在近日的全国竞赛中,小明以其出色的表现获得了一等奖。小明的导师表示,这是西安市的骄傲。 | 2025-12-18 14:06:38 |
| 2 | 城市新闻 | 西安市今日举行了一场大型环保活动。志愿者小明与数百位市民一同参与了清洁工作。本次活动旨在提升市民的环保意识,建设更美丽的西安市。相关部门表示未来将持续举办此类活动。 | 2025-12-18 14:06:38 |
| 3 | 古城动态 | 西安市作为历史文化名城,近年来在城市规划和旅游发展方面取得了显著成就。 | 2025-12-18 14:06:38 |
| 4 | 个人事迹 | 热心市民小明多年来坚持社区志愿服务,他的事迹被广泛报道。 | 2025-12-18 14:06:38 |
| 5 | 都市故事 | 在某个北方大都市,一位名叫张伟的年轻人也取得了类似的成就。 | 2025-12-18 14:06:38 |
+----+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
5 rows in set (0.003 sec)
obclient [test]> SELECT
id,
title,
-- 计算BM25相关性分数,并取两位小数便于阅读
MATCH(content) AGAINST('西安市 小明') AS relevance_score,
LEFT(content, 50) AS content_preview
FROM news_articles
;
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | title | relevance_score | content_preview |
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 小明获奖 | 0.5296221570066031 | 来自西安市的优秀学生小明,在近日的全国竞赛中,小明以其出色的表现获得了一等奖。小明的导师表示,这是西 |
| 2 | 城市新闻 | 0.2986855759252854 | 西安市今日举行了一场大型环保活动。志愿者小明与数百位市民一同参与了清洁工作。本次活动旨在提升市民的环 |
| 3 | 古城动态 | 0.21484375000000006 | 西安市作为历史文化名城,近年来在城市规划和旅游发展方面取得了显著成就。 |
| 4 | 个人事迹 | 0.21484375000000006 | 热心市民小明多年来坚持社区志愿服务,他的事迹被广泛报道。 |
| 5 | 都市故事 | 0 | 在某个北方大都市,一位名叫张伟的年轻人也取得了类似的成就。 |
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
5 rows in set (0.003 sec)
布尔模式:精确找出“包含”或“不包含”某些词的文档。
自然语言模:是找出“最相关”的文档,并按相关性排序。
看完理论想学实操?不用本地部署环境!
PS:关于全文索引的实验,大家可以去OceanBase官网的在线课堂“DBA实战营——第六期”来上手操作。(有在线环境!!!)