×
技术社区 >  技术博客 >  OceanBase 全文索引完全指南:分词器+创建语法+全文查询实战

OceanBase 全文索引完全指南:分词器+创建语法+全文查询实战

日常开发中,我们经常需要检索文章、评论、新闻、商品描述等大段文本内容。

如果还在使用LIKE %关键词%模糊查询,不仅无法命中语义、无法按相关性排序,数据量大时还会出现查询性能暴跌的问题。

针对海量文本检索场景,OceanBase 提供了**全文索引(Fulltext Index)**能力,搭配多类型分词器、两种查询模式,完美适配中英文文本搜索,是业务文本检索的最优解决方案。

今天这篇干货,带你吃透 OceanBase 全文索引:核心概念、使用限制、分词器的基础概念和语法。

全文索引是什么

全文索引(Fulltext Index)是一种专门用于对文本内容(如 CHAR、VARCHAR、TEXT 类型的列)进行高效、灵活搜索的数据库索引。

全文索引通过分词器将大段文本拆分成一个个有意义的“词元”(token),然后基于这些词元建立索引。这使得你可以进行关键词搜索、模糊匹配等复杂的文本查询。让你能在海量文本数据中,快速查找到包含特定单词或短语的记录。

使用限制

  1. 支持的列类型:仅适用于 CHAR、VARCHAR 和 TEXT 类型的列。
  2. 唯一性与数量:
    创建时不能指定 UNIQUE(唯一)关键字。
    允许在一张表上创建多个全文索引,甚至可以对同一列创建多个不同的全文索引。
  3. 分区表支持:当前版本(V4.3.5)只支持创建局部(LOCAL) 全文索引。
  4. 多列索引:如果对多列创建全文索引,这些列必须使用相同的字符集。

创建索引

创建语法

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)是全文索引的核心引擎,它决定了如何将一段文本拆解成可供搜索的最小单元(词元)。

分词器列表:

1、Space 分词器

以空格、标点符号(如逗号、句号)或非字母数字字符(除下划线 _ 外)为分隔符拆分文本。

分词结果仅包含长度在 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)

2、Basic English 分词器 'beng'

与 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)

3、IK 分词器 (从 V4.3.5 BP1 版本开始支持 IK 分词器。)

基于开源工具 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)

4、Ngram 分词器(V4.3.5 BP2 版本开始支持 NGRAM2 分词器。)

固定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实战营——第六期”来上手操作。(有在线环境!!!)

精选推荐