CodeIgniter需手动集成Elasticsearch官方客户端并封装查询逻辑,因其DB类仅支持关系型数据库,$this->db->like()对ES无效;推荐在app/libraries/下建Elasticsearch_lib.php轻量封装,避免过度抽象,并重视数据同步与搜索预处理。

CodeIgniter 本身不提供 Elasticsearch 驱动,必须手动集成 PHP 官方客户端并自行封装查询逻辑。它不像 Laravel Scout 或 Symfony SearchBundle 那样有开箱即用的适配层,所有索引操作、查询构造、结果映射都得你写。
为什么不能直接用 $this->db->like() 查 Elasticsearch
CodeIgniter 的 DB 类只对接 MySQL/PostgreSQL 等关系型数据库,like() 生成的是 SQL 的 WHERE title LIKE '%xxx%';Elasticsearch 没有 SQL,也没有 LIKE 这个语法——它靠 match、term、bool 等 DSL 查询,走的是 HTTP + JSON 协议。
- 调用
$this->db->like()对 ES 完全无效,不会报错但查不到任何东西(因为根本没发请求过去) - 试图把 ES 当成数据库配置进
database.php会直接导致连接失败或Call to undefined method - 想“复用 CI 查询风格”去封装 ES,容易陷入过度抽象,反而让错误定位变难
必须自己写一个轻量级 ES 封装类
推荐在 app/libraries/ 下建 Elasticsearch_lib.php,用官方 elasticsearch/elasticsearch 客户端初始化连接,暴露几个关键方法:
-
search($index, $query, $params = []):统一入口,接收原生 DSL 数组 -
suggest($index, $field, $text):补全建议,调completion或phrasesuggest -
indexDocument($index, $id, $data):写入单条文档,用于同步 MySQL 数据 - 避免封装成“ActiveRecord 风格”,比如
where('title', 'xxx')->get()—— DSL 太灵活,硬套会漏掉should、filter、boost等关键能力
示例片段:
$client = ClientBuilder::create()
->setHosts(['http://es-host:9200'])
->build();
$params = [
'index' => 'articles',
'body' => [
'query' => [
'bool' => [
'must' => [['match' => ['title' => $keyword]]],
'filter' => [['range' => ['created_at' => ['gte' => 'now-30d']]]]
]
]
]
];
$response = $client->search($params);
数据同步是最大隐性成本,别指望实时双写
CI 项目通常以 MySQL 为唯一数据源,ES 只是检索副本。同步方式选错,搜索结果就永远滞后或不一致:
- 不要在 CI 的
insert()/update()后直接调 ES 写入 —— 事务失败时 ES 已写入,造成脏数据 - 简单场景可用定时任务:
php index.php tools sync_articles,每 5 分钟拉一次 MySQL 的updated_at > last_sync记录 - 高一致性要求必须引入消息队列(如 Redis List 或 RabbitMQ),CI 写库成功后推消息,由独立 worker 消费并更新 ES
- 注意字段类型映射:MySQL 的
TEXT字段在 ES 中要设为"type": "text", "analyzer": "ik_smart"(中文),否则match查不到
搜索关键词处理必须前置,不能全丢给 ES
用户搜 “ci框架 教程”,ES 默认会分词成 [“ci”, “框架”, “教程”],但“ci”可能被误判为“CI/CD”或缩写——这需要你在 CI 层做预处理:
- 敏感词过滤:
str_replace(['php', 'mysql'], '', $keyword)(若业务禁止这些词) - 同义词扩展:查配置表把 “ci” → “codeigniter”,再拼到
should子句里 - 拼音支持:用
pinyin扩展把 “codeigniter” → “ci yin ter”,加进multi_match的fields - 长度截断:ES 对超长 query 解析慢,前端传入超过 100 字符应直接
return []或截断
真正难的不是连上 ES,而是让“用户随便输”和“系统稳定返回相关结果”之间不脱节——这个平衡点,得在 CI 的 Controller 和 Library 里一处处调出来。











