首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

基於 MySQL 的 UTF-8 中文全文檢索實現:分詞 + 編碼 + FULLTEXT 索引

     編輯:MySQL 資料庫相關知識

痛點分析

  • MySQL 內建 FULLTEXT 僅支持空格分詞語言(英文等)
  • 中文無分隔符,直接建索引將整段文本視為一個 Token,檢索失效
  • LIKE '%關鍵字%' 全表掃描,十萬級數據耗時 10 秒+,體驗極差

解決方案架構:分詞 → 編碼 → FULLTEXT

用戶輸入中文 → SCWS 分詞 → URLEncode 編碼 → 空格連接 → 寫入 FULLTEXT 索引表
                    ↑
            搜索時同樣處理,直接 MATCH AGAINST

核心組件

1. 雙表結構

-- 業務表
CREATE TABLE members (
    user_id INT PRIMARY KEY,
    user_name VARCHAR(50),
    user_introduction TEXT
) ENGINE=InnoDB;

-- 索引表 (僅存編碼後 Token)
CREATE TABLE members_index (
    user_id INT PRIMARY KEY,
    index_intro TEXT,
    FULLTEXT INDEX ft_intro (index_intro)
) ENGINE=MyISAM;  -- 5.6 前 FULLTEXT 僅 MyISAM 支持

2. SCWS 中文分詞 (PHP 擴展)

function str_fc($str) {
    $so = scws_new();
    $so->set_charset('utf8');
    $so->send_text($str);
    $mystr = '';
    while ($tmp = $so->get_result()) {
        foreach ($tmp as $ss) {
            $s = trim($ss['word']);
            if ($s) $mystr .= $s . ' ';
        }
    }
    return $mystr;
}

3. 編碼與去重存儲

$tokens = str_fc($intro);                    // "北京 大學 計算機 系 "
$arr = array_filter(explode(' ', $tokens));  // 去空
$arr = array_flip(array_flip($arr));         // 去重

$encoded = '';
foreach ($arr as $token) {
    if (strlen($token) > 1) {                // 單字過濾可選
        $encoded .= str_replace('%', '', urlencode($token)) . ' ';
    }
}
// $encoded 如: "E58C97E4BAACE5A4A7E5ADA6 E8AEA1E7AE97E69CBA E7B3BB "
// 存入 members_index.index_intro

關鍵點:urlencode 產生的 % 是 MySQL 通配符,**必須移除**,否則 MATCH 語法錯誤。

4. 搜索流程

-- 用戶輸入 "北京 大學"
$kw_encoded = str_replace('%', '', urlencode(str_fc('北京 大學')));
// "E58C97E4BAACE5A4A7E5ADA6 "

-- SQL
SELECT m.* FROM members m
JOIN members_index mi ON m.user_id = mi.user_id
WHERE MATCH(mi.index_intro) AGAINST('$kw_encoded' IN BOOLEAN MODE);

性能與優化

生產級增強方案

  1. 異步更新:業務寫入 → 消息隊列 → Worker 分詞編碼更新索引表,解耦寫入延遲
  2. 增量重建:定期 OPTIMIZE TABLE members_index 整理碎片
  3. 停用詞過濾:分詞階段過濾「的、了、在」等高頻無意義詞
  4. 權重區分:標題/標籤 權重 > 正文,可構造 index_intro = title_tokens*3 + tag_tokens*2 + body_tokens
  5. 遷移建議:MySQL 5.7.6+ / 8.0 內建 ngram parser,
    CREATE FULLTEXT INDEX ft ON t(col) WITH PARSER ngram; 免去外部分詞依賴

替代方案對比

指標優化前 (LIKE)優化後 (FULLTEXT)
10萬條數據查詢耗時~10 秒< 0.5 秒
索引體積無原文本 ~30-50%
實時性即時需同步更新索引表
方案優勢劣勢適用場景
MySQL ngram (5.7+)零依賴、原生、實時索引大、不支持詞級精準匹配中小型、避免外部組件
Elasticsearch專業分詞、分布式、聚合分析運維複雜、數據同步延遲大規模、復雜檢索需求
Sphinx/ManticoreMySQL 友好、增量索引、SQL 接口功能較 ES 弱MySQL 深度綁定、近實時
本文方案 (分詞+編碼)輕量、無新組件、MySQL 5.1+ 通用需維護同步、編碼體積大舊版本遷移、輕量級項目
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved