Sphinx 中文全文搜索引擎

FreeGuideOnline 最新 2026-07-09

bash

Ubuntu/Debian

sudo apt update sudo apt install -y build-essential libmysqlclient-dev libexpat1-dev

CentOS/RHEL

sudo yum install -y gcc gcc-c++ make mysql-devel expat-devel


---

## 安装与编译 Sphinx

从官网下载 Sphinx 源码包,编译并安装(以 3.3.1 为例):

```bash
wget http://sphinxsearch.com/files/sphinx-3.3.1-3b5c8ad-linux-amd64.tar.gz
tar -xzf sphinx-3.3.1-3b5c8ad-linux-amd64.tar.gz
cd sphinx-3.3.1

# 编译安装
./configure --prefix=/usr/local/sphinx --with-mysql
make
sudo make install

安装完成后,将 /usr/local/sphinx/bin 添加到 PATH:

echo 'export PATH=/usr/local/sphinx/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

集成中文分词器(jieba)

Sphinx 原生不支持中文分词,但可以通过 mmseg 的词典接口加载自定义词库。最简便的方式是使用 sphinx-jieba 扩展。

下载并编译 sphinx-jieba

git clone https://github.com/yanyiwu/sphinx-jieba.git
cd sphinx-jieba
# 修改 Makefile 中的 SPHINX_INC 和 SPHINX_LIB 指向你的 Sphinx 安装路径
make

编译完成后会得到 libsphinx-jieba.so,将其复制到 Sphinx 的插件目录(或其他可加载路径):

sudo cp libsphinx-jieba.so /usr/local/sphinx/lib/

同时需要准备 jieba 的词库文件(dict.txt.big 等),可以从 jieba 官方仓库获取,或者使用你训练好的词库。

配置 Sphinx 数据源与索引

Sphinx 使用配置文件 sphinx.conf 定义数据来源、索引结构和搜索行为。我们创建一个支持中文分词的索引。

示例数据库

假设你的 MySQL 中有一张 articles 表,字段 id, title, content,我们将对 titlecontent 建立全文索引。

CREATE TABLE articles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255),
    content TEXT
);

编写 sphinx.conf

# 数据源定义
source src_articles {
    type            = mysql
    sql_host        = localhost
    sql_user        = root
    sql_pass        = yourpassword
    sql_db          = test
    sql_port        = 3306
    sql_query       = SELECT id, title, content FROM articles
    sql_attr_uint   = id
}

# 索引定义
index idx_articles {
    source          = src_articles
    path            = /usr/local/sphinx/var/data/idx_articles
    docinfo         = extern
    morphology      = none               # 不使用内置词干分析
    charset_type    = utf-8
    charset_table   = 0..9, A..Z->a..z, _, a..z, \
                      U+4E00..U+9FFF, \   # 中文字符范围
                      U+3400..U+4DBF
    # 指定自定义分词器
    mlock           = 0
    min_word_len    = 1
    # 中文分词插件
    index_sp        = 1
    index_field_lengths = 1
    # 使用 jieba 分词插件
    plugin_dir      = /usr/local/sphinx/lib
    # 定义 token filter
    token_filter    = jieba
    # jieba 分词器配置
    token_filter_jieba {
        type        = plugin
        plugin      = libsphinx-jieba.so
        # 词库路径
        conf        = /path/to/jieba/dict/jieba.dict.utf8
        hmm         = /path/to/jieba/dict/hmm_model.utf8
        user        = /path/to/jieba/dict/user.dict.utf8
        idf         = /path/to/jieba/dict/idf.utf8
        stop        = /path/to/jieba/dict/stop_words.utf8
    }
}

# 搜索守护进程
searchd {
    listen          = 9312
    log             = /usr/local/sphinx/var/log/searchd.log
    query_log       = /usr/local/sphinx/var/log/query.log
    pid_file        = /usr/local/sphinx/var/log/searchd.pid
    seamless_rotate = 1
    preopen_indexes = 1
    unlink_old      = 1
    workers         = threads
}

注意:以上 token_filter_jieba 配置在 Sphinx 3.x 中可能需要根据实际插件接口微调。对于旧版 Sphinx 2.x,通常会使用 charset_table 配合 dict 方式,或者通过 indexer --buildstops 生成手工分词。如果你使用的是 Sphinx 2.2.11,可以通过第三方 mmseg 插件实现分词。

如果你的 Sphinx 版本较旧,可以尝试另一种简单方法:使用外部预处理脚本将中文文本按分词结果用空格分隔,再存储到数据库中,这样 Sphinx 就可以直接使用 charset_table 加上空格分隔的词语进行索引。

索引创建与测试

配置文件写好后,创建索引:

indexer idx_articles --config /usr/local/sphinx/etc/sphinx.conf --rotate

如果索引顺利建完,启动搜索守护进程:

searchd --config /usr/local/sphinx/etc/sphinx.conf

现在可以用 MySQL 客户端或 PHP、Python 等语言连接 Sphinx 进行搜索。Sphinx 的查询接口使用类 SQL 语法,通过 9312 端口。

通过 MySQL 客户端搜索

mysql -h 0 -P 9306

在 SphinxQL 中测试:

SELECT * FROM idx_articles WHERE MATCH('搜索引擎') LIMIT 10;

如果返回相关文章 ID 和权重,说明中文分词和搜索正常工作。

常见问题与优化

1. 分词结果不符合预期

  • 检查 jieba 词库路径是否正确,用户自定义词典是否加载。
  • 可通过 CALL KEYWORDS('搜索词', 'idx_articles') 查看 Sphinx 实际切分出的词条,验证分词效果。

2. 中文短语匹配不精确

  • 在 Sphinx 中,默认使用 phrase 操作符进行短语搜索:MATCH('"搜索引擎"') 会匹配精确顺序的词。
  • 调整 min_infix_len 参数可以启用中缀匹配,实现部分词匹配,但会显著增加索引大小。

3. 性能调优

  • 使用 ondisk_dict 启用字典的磁盘存储,节省内存。
  • 调整 indexer 的内存限制 mem_limit
  • 对大型数据集,启用实时索引(RT index)以支持快速增量更新。

4. 实时索引配置示例

如果需要频繁更新数据,使用实时索引更加灵活:

index rt_articles {
    type            = rt
    path            = /usr/local/sphinx/var/data/rt_articles
    rt_field        = title
    rt_field        = content
    rt_attr_uint    = id
    # 中文分词配置同上
    token_filter    = jieba
    # ... 其他分词设置
}

插入数据:

INSERT INTO rt_articles (id, title, content) VALUES (1, 'Sphinx教程', '这是一个中文全文搜索的详细教程');