Jieba-PHP 分词使用
解读
在国内 PHP 面试中,面试官问“Jieba-PHP 分词使用”并不是想听你背源码,而是考察三件事:
- 是否知道中文分词对业务的价值(搜索、推荐、关键词提取、敏感词过滤);
- 能否在 PHP 端独立落地,不依赖 Python 服务;
- 是否具备“工程化”思维:词典扩展、性能调优、高并发场景下的稳定性。
因此,回答要围绕“安装→加载词典→三种切分模式→自定义词典→性能优化→线上踩坑”这条主线展开,并给出可落地的代码片段。
知识点
- Jieba-PHP 本质:用 PHP 重写的“结巴”算法,支持 DAG+HMM 两种模型,无 Python 依赖。
- 三种模式:
精确模式:试图将句子最精确地切开,适合文本分析;
全模式:把句子中所有可能是词语的都扫描出来,速度非常快,但不能解决歧义;
搜索引擎模式:在精确模式基础上,对长词再次切分,提高召回率,适用于搜索引擎倒排。 - 词典文件:dict.txt 每行“词语 词频 词性”,UTF-8 无 BOM;自定义词典热加载无需重启进程。
- 性能瓶颈:每次 new Jieba() 会重新加载 3 M 词典,并发高时 CPU 飙高;需用单例 + Opcache 预加载。
- 与 Composer 集成:官方包“fxsjy/jieba-php”已停止维护,国内镜像推荐“yunke-jieba/jieba-php”,require 后自动注册 PSR-4。
- 与 Swoole/FPM 差异:Swoole 常驻内存,必须在 WorkerStart 阶段一次性加载词典;FPM 下可借助 php-fpm 的 preload 功能。
- 业务扩展:敏感词过滤可再封装一个 Trie 树,分词后遍历匹配;关键词提取用 TF-IDF 或 TextRank,Jieba-PHP 自带 TF-IDF 实现。
答案
“我去年在电商搜索项目中用 Jieba-PHP 替换了原来调用 Python 接口的方案,QPS 从 800 提到 3200,核心步骤如下:
- Composer 引入:
composer require yunke-jieba/jieba-php - 封装单例服务,在框架启动时一次性加载词典:
class JiebaService
{
private static jieba;
private function __construct()
{
\Jieba::init(['mode'=>'default','dict'=>'small']); // 用 small 词典省 40% 内存
\Finalseg::init();
this->jieba = new \Jieba(); } public static function getInstance(): self { return self::instance ?? (self::instance = new self()); } public function cut(string text, bool search=false): array { return search ? \Jieba::cutForSearch(text);
}
} - 自定义词典:把品牌词、类目词放到 storage/dict/user.dict.txt,上线前用
\Jieba::loadUserDict(storage_path('dict/user.dict.txt'));
这样“iPhone15ProMax”不会被切成“iPhone/15/Pro/Max”。 - 性能调优:
– 开启 OPcache,把 JiebaService 放入 preload 列表;
– Swoole 环境把 init 放在 onWorkerStart,杜绝重复加载;
– 对 50 字以上长文本先按标点粗切,再并行调用 cut,降低单次耗时。 - 线上监控:
– 每 10 秒采集一次分词平均耗时,>20ms 自动告警;
– 词典热更新通过 etcd 下发版本号,对比 md5 后 reload,做到秒级生效。
最终搜索转化率提升 2.3%,服务器节省 8 台,整个方案完全 PHP 闭环,无需额外 Python 微服务。”
拓展思考
- 如果业务需要新词发现,可以把每日用户查询日志用 Jieba-PHP 全模式粗切,再统计共现熵,自动补充到 user.dict,实现“自适应词典”。
- 当单机内存不足时,可把词典按首字哈希拆成 16 个文件,用 mmap 局部加载,内存占用从 3 M 降到 400 K,适合容器化多实例。
- 分词只是第一步,后续可接 PHP 版的 TextRank 提取关键词,再用 FastText 做意图分类,整套链路纯 PHP,方便运维。