日常開(kāi)發(fā)中,我們經(jīng)常需要檢索文章、評(píng)論、新聞、商品描述等大段文本內(nèi)容。
如果還在使用LIKE %關(guān)鍵詞%模糊查詢,不僅無(wú)法命中語(yǔ)義、無(wú)法按相關(guān)性排序,數(shù)據(jù)量大時(shí)還會(huì)出現(xiàn)查詢性能暴跌的問(wèn)題。
針對(duì)海量文本檢索場(chǎng)景,OceanBase 提供了**全文索引(Fulltext Index)**能力,搭配多類(lèi)型分詞器、兩種查詢模式,完美適配中英文文本搜索,是業(yè)務(wù)文本檢索的最優(yōu)解決方案。
今天這篇干貨,帶你吃透 OceanBase 全文索引:核心概念、使用限制、分詞器的基礎(chǔ)概念和語(yǔ)法。
全文索引是什么
全文索引(Fulltext Index)是一種專門(mén)用于對(duì)文本內(nèi)容(如 CHAR、VARCHAR、TEXT 類(lèi)型的列)進(jìn)行高效、靈活搜索的數(shù)據(jù)庫(kù)索引。
全文索引通過(guò)分詞器將大段文本拆分成一個(gè)個(gè)有意義的“詞元”(token),然后基于這些詞元建立索引。這使得你可以進(jìn)行關(guān)鍵詞搜索、模糊匹配等復(fù)雜的文本查詢。讓你能在海量文本數(shù)據(jù)中,快速查找到包含特定單詞或短語(yǔ)的記錄。
使用限制
- 支持的列類(lèi)型:僅適用于 CHAR、VARCHAR 和 TEXT 類(lèi)型的列。
- 唯一性與數(shù)量:
創(chuàng)建時(shí)不能指定 UNIQUE(唯一)關(guān)鍵字。
允許在一張表上創(chuàng)建多個(gè)全文索引,甚至可以對(duì)同一列創(chuàng)建多個(gè)不同的全文索引。
- 分區(qū)表支持:當(dāng)前版本(V4.3.5)只支持創(chuàng)建局部(LOCAL) 全文索引。
- 多列索引:如果對(duì)多列創(chuàng)建全文索引,這些列必須使用相同的字符集。
創(chuàng)建索引
創(chuàng)建語(yǔ)法
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)
-- 建表時(shí)創(chuàng)建 默認(rèn)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 分詞器
以空格、標(biāo)點(diǎn)符號(hào)(如逗號(hào)、句號(hào))或非字母數(shù)字字符(除下劃線 _ 外)為分隔符拆分文本。
分詞結(jié)果僅包含長(zhǎng)度在 min_token_size(默認(rèn) 3)到 max_token_size(默認(rèn) 84)之間的有效詞元。
中文字符被視為單個(gè)字符處理。
示例
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 分詞器類(lèi)似,但不保留下劃線 _,將其視為分隔符。
適用于英文短語(yǔ)分隔,但對(duì)無(wú)空格術(shù)語(yǔ)(如 “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 版本開(kāi)始支持 IK 分詞器。)
基于開(kāi)源工具 IK Analyzer 的中文分詞器,支持兩種模式:
Smart 模式:優(yōu)先輸出長(zhǎng)詞,減少切分?jǐn)?shù)量 (如“南京市”不切分為“南京”“市”)。
Max Word 模式:輸出所有可能的短詞(如“南京市”切分為“南京”“市”)。
自動(dòng)識(shí)別英文單詞、郵箱、URL(不含 ://)、IP 地址等格式。
示例
-- smart模式
obclient [test] select tokenize('全文索引通過(guò)分詞器將大段文本拆分成一個(gè)個(gè)有意義的“詞元”(token),然后基于這些詞元建立索引。','IK','[{"additional_args":[{"ik_mode": "smart"}]}]') as space_token;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["索引", "建立", "這些", "基于", "然后", "token", "元", "詞", "的", "有意義", "一個(gè)個(gè)", "分成", "拆", "文本", "大段", "將", "分詞器", "通過(guò)", "全文索引"] |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
-- max_word模式
obclient [test] select tokenize('全文索引通過(guò)分詞器將大段文本拆分成一個(gè)個(gè)有意義的“詞元”(token),然后基于這些詞元建立索引。','IK','[{"additional_args":[{"ik_mode": "max_word"}]}]') as space_token;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["建立", "這些", "基于", "然后", "token", "元", "詞", "的", "意義", "有意", "有意義", "個(gè)", "個(gè)個(gè)", "一", "一個(gè)", "一個(gè)個(gè)", "分成", "拆分", "文本", "大段", "將", "器", "分詞", "分詞器", "過(guò)分", "通過(guò)", "索引", "全文", "全文索引"] |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
4、Ngram 分詞器(V4.3.5 BP2 版本開(kāi)始支持 NGRAM2 分詞器。)
固定n值分詞:默認(rèn) n=2,將連續(xù)非分隔符字符拆分為長(zhǎng)度為 n 的子序列。
分隔符判定規(guī)則同 Space 分詞器(保留 _ 和數(shù)字字母)。
不支持長(zhǎng)度限制參數(shù),輸出所有可能的 n 長(zhǎng)度詞元。
示例
select tokenize('全文索引','NGRAM') as space_token;
+--------------------------------+
| space_token |
+--------------------------------+
| ["索引", "文索", "全文"] |
+--------------------------------+
1 row in set (0.000 sec)
obclient [test] select tokenize('全文索引通過(guò)分詞器將大段文本拆分成一個(gè)個(gè)有意義的“詞元”(token),然后基于這些詞元建立索引。','NGRAM') as space_token;
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| space_token |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ["立索", "建立", "元建", "些詞", "這些", "于這", "基于", "后基", "然后", "en", "ke", "ok", "to", "詞元", "義的", "意義", "有意", "個(gè)有", "個(gè)個(gè)", "一個(gè)", "成一", "分成", "拆分", "本拆", "文本", "段文", "大段", "將大", "器將", "詞器", "分詞", "過(guò)分", "通過(guò)", "引通", "索引", "文索", "全文"] |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
| 分詞器 |
主要特點(diǎn) |
適應(yīng)場(chǎng)景 |
| Space 分詞器 (默認(rèn)) |
以空格、標(biāo)點(diǎn)分隔(除了下劃線_) |
英文等以空格分隔的語(yǔ)言。 |
| IK 分詞器 |
專為中文設(shè)計(jì),支持smart和max_word(全切分)模式,能識(shí)別郵箱、URL等。 |
中文文本搜索,如商品描述、評(píng)論分析。 |
| Ngram 分詞器 |
按固定長(zhǎng)度(如2個(gè)字符)機(jī)械切分,不依賴詞典。 |
短文本模糊匹配,如產(chǎn)品型號(hào)、用戶ID。 |
| Ngram2 分詞器 |
支持動(dòng)態(tài)長(zhǎng)度范圍切分,但內(nèi)存消耗可能較高。 |
需要同時(shí)匹配多種長(zhǎng)度詞元的場(chǎng)景。 |
全文查詢是什么
全文查詢是指在文本數(shù)據(jù)中進(jìn)行全文搜索或檢索的操作。它用于查找包含特定關(guān)鍵詞、短語(yǔ)或文本表達(dá)式的文本內(nèi)容。全文查詢能夠更全面地搜索整個(gè)文本,并返回與搜索條件匹配的結(jié)果。
語(yǔ)法
MATCH (column_name [, column_name ...]) AGAINST (expr [search_modifier])
search_modifier:
IN NATURAL LANGUAGE MODE
| IN BOOLEAN MODE
IN NATURAL LANGUAGE MODE:默認(rèn)值,用于指定使用自然語(yǔ)言搜索模式進(jìn)行搜索。該模式的全文搜索是通過(guò)對(duì)查詢表達(dá)式(query_expr)進(jìn)行分詞得到詞條(token)集合,與索引中的詞條(token)進(jìn)行匹配來(lái)進(jìn)行檢索,只要有一個(gè)詞條與查詢表達(dá)式中的詞條匹配成功就視為匹配成功。同時(shí)會(huì)通過(guò)基于詞頻的方法(Okapi BM25)對(duì)被匹配成功的行相關(guān)性進(jìn)行 ranking(排序)。
默認(rèn)情況下或者指定 IN NATURAL LANGUAGE MODE 標(biāo)示符,MATCH AGAINST 將使用 NATURAL LANGUAGE 模式來(lái)進(jìn)行全文查找。在 NATURAL LANGUAGE 模式下,AGAINST 接受一個(gè)查找字符串,并且按照字符集的比較方式在索引中進(jìn)行查找,對(duì)于表中的每一行數(shù)據(jù),MATCH 的返回值代表了查找字符串和行中數(shù)據(jù)的相關(guān)度,也就是查找字符串中的文本和數(shù)據(jù)表中的文本相似度。
IN BOOLEAN MODE:用于指定使用布爾模式進(jìn)行搜索。當(dāng)前版本支持三種最常用的布爾運(yùn)算符,以及運(yùn)算嵌套,具體如下:
+:表示 AND,交集。
-:表示非,差集。
無(wú)操作符號(hào):?jiǎn)为?dú)使用時(shí)表示 OR,并集,如 A B 表示 A OR B。和符號(hào)混用會(huì)讓存在的句子相關(guān)性變高,但會(huì)失去 OR 的語(yǔ)意,如 +A B 時(shí),表示必須有 A,并計(jì)算句子中 A 和 B 的相關(guān)性。
():表示運(yùn)算嵌套。外層無(wú)符號(hào)時(shí),有 OR 的語(yǔ)意,如 +A (嵌套子句),表示必須有 A 或者有嵌套子句。
示例
obclient [test] CREATE TABLE news_articles (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(200) NOT NULL COMMENT '新聞標(biāo)題',
-- 使用TEXT類(lèi)型存儲(chǔ)新聞?wù)模@是全文索引的主要目標(biāo)列
content TEXT NOT NULL COMMENT '新聞?wù)?,
publish_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '發(fā)布時(shí)間',
-- 為content列創(chuàng)建全文索引,使用IK分詞器(假設(shè)已安裝支持)
-- 關(guān)鍵:FULLTEXT INDEX 和 WITH PARSER 子句
FULLTEXT INDEX ft_idx_content (content) WITH PARSER IK
) COMMENT='新聞測(cè)試表' 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:高度相關(guān),兩個(gè)關(guān)鍵詞都出現(xiàn)且“小明”多次出現(xiàn)
('小明獲獎(jiǎng)', '來(lái)自西安市的優(yōu)秀學(xué)生小明,在近日的全國(guó)競(jìng)賽中,小明以其出色的表現(xiàn)獲得了一等獎(jiǎng)。小明的導(dǎo)師表示,這是西安市的驕傲。'),
-- 文檔B:相關(guān),但關(guān)鍵詞出現(xiàn)次數(shù)少,文檔更長(zhǎng)(稀釋了密度)
('城市新聞', '西安市今日舉行了一場(chǎng)大型環(huán)保活動(dòng)。志愿者小明與數(shù)百位市民一同參與了清潔工作。本次活動(dòng)旨在提升市民的環(huán)保意識(shí),建設(shè)更美麗的西安市。相關(guān)部門(mén)表示未來(lái)將持續(xù)舉辦此類(lèi)活動(dòng)。'),
-- 文檔C:只包含一個(gè)關(guān)鍵詞
('古城動(dòng)態(tài)', '西安市作為歷史文化名城,近年來(lái)在城市規(guī)劃和旅游發(fā)展方面取得了顯著成就。'),
-- 文檔D:包含“小明”但不包含“西安市”
('個(gè)人事跡', '熱心市民小明多年來(lái)堅(jiān)持社區(qū)志愿服務(wù),他的事跡被廣泛報(bào)道。'),
-- 文檔E:包含同義詞但無(wú)精確關(guān)鍵詞
('都市故事', '在某個(gè)北方大都市,一位名叫張偉的年輕人也取得了類(lèi)似的成就。');
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 | 小明獲獎(jiǎng) | 來(lái)自西安市的優(yōu)秀學(xué)生小明,在近日的全國(guó)競(jìng)賽中,小明以其出色的表現(xiàn)獲得了一等獎(jiǎng)。小明的導(dǎo)師表示,這是西安市的驕傲。 | 2025-12-18 14:06:38 |
| 2 | 城市新聞 | 西安市今日舉行了一場(chǎng)大型環(huán)保活動(dòng)。志愿者小明與數(shù)百位市民一同參與了清潔工作。本次活動(dòng)旨在提升市民的環(huán)保意識(shí),建設(shè)更美麗的西安市。相關(guān)部門(mén)表示未來(lái)將持續(xù)舉辦此類(lèi)活動(dòng)。 | 2025-12-18 14:06:38 |
| 3 | 古城動(dòng)態(tài) | 西安市作為歷史文化名城,近年來(lái)在城市規(guī)劃和旅游發(fā)展方面取得了顯著成就。 | 2025-12-18 14:06:38 |
| 4 | 個(gè)人事跡 | 熱心市民小明多年來(lái)堅(jiān)持社區(qū)志愿服務(wù),他的事跡被廣泛報(bào)道。 | 2025-12-18 14:06:38 |
| 5 | 都市故事 | 在某個(gè)北方大都市,一位名叫張偉的年輕人也取得了類(lèi)似的成就。 | 2025-12-18 14:06:38 |
+----+--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+
5 rows in set (0.003 sec)
obclient [test]> SELECT
id,
title,
-- 計(jì)算BM25相關(guān)性分?jǐn)?shù),并取兩位小數(shù)便于閱讀
MATCH(content) AGAINST('西安市 小明') AS relevance_score,
LEFT(content, 50) AS content_preview
FROM news_articles
;
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | title | relevance_score | content_preview |
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 小明獲獎(jiǎng) | 0.5296221570066031 | 來(lái)自西安市的優(yōu)秀學(xué)生小明,在近日的全國(guó)競(jìng)賽中,小明以其出色的表現(xiàn)獲得了一等獎(jiǎng)。小明的導(dǎo)師表示,這是西 |
| 2 | 城市新聞 | 0.2986855759252854 | 西安市今日舉行了一場(chǎng)大型環(huán)保活動(dòng)。志愿者小明與數(shù)百位市民一同參與了清潔工作。本次活動(dòng)旨在提升市民的環(huán) |
| 3 | 古城動(dòng)態(tài) | 0.21484375000000006 | 西安市作為歷史文化名城,近年來(lái)在城市規(guī)劃和旅游發(fā)展方面取得了顯著成就。 |
| 4 | 個(gè)人事跡 | 0.21484375000000006 | 熱心市民小明多年來(lái)堅(jiān)持社區(qū)志愿服務(wù),他的事跡被廣泛報(bào)道。 |
| 5 | 都市故事 | 0 | 在某個(gè)北方大都市,一位名叫張偉的年輕人也取得了類(lèi)似的成就。 |
+----+--------------+---------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
5 rows in set (0.003 sec)
布爾模式和自然語(yǔ)言模式的主要區(qū)別:
布爾模式:精確找出“包含”或“不包含”某些詞的文檔。
自然語(yǔ)言模:是找出“最相關(guān)”的文檔,并按相關(guān)性排序。
看完理論想學(xué)實(shí)操?不用本地部署環(huán)境!
PS:關(guān)于全文索引的實(shí)驗(yàn),大家可以去OceanBase官網(wǎng)的在線課堂“DBA實(shí)戰(zhàn)營(yíng)——第六期”來(lái)上手操作。(有在線環(huán)境!!!)