必须用elasticsearch-php客户端替代CI原生HTTP工具,配IK分词器并统一analyzer,通过异步队列实现MySQL与ES最终一致,查询须严格按ES DSL拼body。

CodeIgniter 本身不处理 Elasticsearch,所有操作都得绕过框架封装,直接用 PHP 客户端发请求;数据不同步、中文分词没配好、查询写成 match 却没设 analyzer,这三样加一起,搜出来全是空或乱序结果。
怎么装客户端并连上 Elasticsearch
别碰 CI 自带的 curl 类或手写 file_get_contents() —— 没重试、没连接池、没错误上下文。必须用官方维护的 elasticsearch-php 客户端。
- 用 Composer 装:运行
composer require elasticsearch/elasticsearch(注意版本对齐:PHP 8.1+ 对应 v8.x,ES 8.x 集群不能混用 v7 客户端) - 初始化时显式关掉 SSL 验证(开发环境):
->setHosts(['https://es-host:9200'])->setSSLVerification(false),否则 curl 报CURLOPT_SSL_VERIFYPEER错误 - 生产环境必须配证书路径:
->setSSLVerification('/path/to/ca.crt'),不然连不上启用了 TLS 的集群
为什么中文搜索总返回空或错乱
ES 默认的 standard 分词器把“全文检索”切成 ['全','文','检','索'],但用户搜“全文”时,它根本匹配不到完整词——这不是 CI 的问题,是分词器没换。
- 必须在 ES 里装
ik插件(v8.x 对应 ik 8.13.0),重启节点后验证:GET /_cat/plugins?v看输出含ik - 建索引时指定
analyzer:"title": {"type": "text", "analyzer": "ik_max_word"},别漏掉search_analyzer,否则写入和查询分词不一致 - CI 中发查询时,
match必须带analyzer参数:'match' => ['title' => ['query' => $keyword, 'analyzer' => 'ik_smart']]
怎么避免 MySQL 和 ES 数据不一致
没人能靠事务跨 MySQL 和 ES 保证强一致;双写失败就丢数据,监听 binlog 又太重。最务实的做法是接受最终一致,并控制延迟在可接受范围。
- 不要在 CI 的 Model
insert()里同步调 ESindex()—— 一旦 ES 挂了,主业务就失败 - 改用异步队列:CI 写完 MySQL 后,往 Redis 队列推一条
{'table':'articles','id':123,'action':'upsert'},另起一个 CLI 脚本消费队列并批量同步到 ES - 关键字段加
updated_at时间戳,同步脚本定期扫WHERE updated_at > ?的增量数据,比监听更稳、更易 debug
查询参数怎么写才不出 bug
CI 的 like() 或 where() 对 ES 完全无效;所有查询都得拼 body 数组,稍错一个 key 就 400 或空结果。
-
multi_match比match更常用,但字段列表必须存在且类型为text:'multi_match' => ['query' => $q, 'fields' => ['title^3', 'content']] - 过滤时间范围别用
must套range,改用filter:'filter' => [['range' => ['created_at' => ['gte' => 'now-30d']]]],否则影响相关度打分 - 高亮必须显式开:
'highlight' => ['fields' => ['title' => new \stdClass(), 'content' => new \stdClass()]],且字段 mapping 得设"highlight": true
真正难的不是写几行 search() 调用,而是分词器选型、mapping 设计、同步策略取舍——这些都在 CI 框架之外,但每一步错了,搜出来的东西就不可信。


















