Yii框架本身不内置Elasticsearch支持,必须通过yii2-elasticsearch等扩展接入;官方扩展提供ActiveRecord风格接口,安装需注意Yii、ES及PHP SDK版本对齐,ES 8.x需禁用SSL或配置认证,模型字段须严格匹配mapping,中文检索依赖IK分词器预设analyzer。

Yii 框架本身不内置 Elasticsearch 支持,必须通过扩展(如 yii2-elasticsearch)接入;直接调用 REST API 或硬编码 HTTP 请求是常见但易出错的替代方案,不推荐用于生产。
怎么装 yii2-elasticsearch 扩展
官方维护的 yii2-elasticsearch 是 Yii2 官方推荐的 ES 客户端封装,它基于 Elasticsearch-PHP SDK,提供 ActiveRecord 风格的查询接口。安装时注意版本对齐:
- Yii 2.0.x 对应
yii2-elasticsearch:~2.1(适配 ES 6.x–7.x) - 若你用的是 ES 8.x(如阿里云向量增强版 8.17.0),需确认
elasticsearch/elasticsearchPHP SDK 版本 ≥ 8.0,否则会报400 Bad Request: Content-Type header is missing或index_not_found_exception - 执行命令:
composer require yiisoft/yii2-elasticsearch:~2.1(不要用 dev-main) - 在
config/web.php或config/main.php中注册组件:
'components' => [
'elasticsearch' => [
'class' => 'yii\elasticsearch\Connection',
'nodes' => [
['http_address' => '192.168.70.129:9200'],
],
],
],
注意:ES 8.x 默认启用 HTTPS 和认证,若你本地测试未开安全功能,要显式加 'ssl' => false,否则连接会卡住或抛 cURL error 35。
怎么定义 Elasticsearch ActiveRecord 模型
Yii 的 ActiveRecord 抽象层在 ES 场景下只负责结构映射和基础 CRUD,不处理分词、analyzers 或 mapping 定义——这些必须提前在 ES 端创建好索引并设好 mapping,PHP 层只读取字段名与类型做校验。
- 继承
yii\elasticsearch\ActiveRecord,重写index()返回索引名(如'article'),type()在 ES 7+ 可返回空字符串或忽略(因 type 已废弃) - 字段声明用
attributes()方法,仅声明 ES mapping 中已存在的text、keyword、date等字段,不要多写——否则save()会静默丢弃未声明字段 - 中文全文检索必须依赖 IK 分词器,但 Yii 层无法控制
analyzer,所以title字段在 ES mapping 中得这样设:
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
否则你在 Yii 里用 where(['match' => ['title' => '搜索词']]) 也查不到结果——因为默认 standard 分词器把中文切成了单字。
怎么写带中文分词的搜索查询
Yii 的 yii\elasticsearch\Query 封装了 DSL,但不自动适配中文语义。最常用且可控的方式是手写 body 数组传给 search(),而不是依赖 where() 链式调用。
- 避免用
andFilterWhere(['match' => [...]]):它生成的 query_string 不指定analyzer,容易匹配失败 - 推荐用
Query::create()->addSelect(...)->addFilter(...)或直接构造 body:
$query = new \yii\elasticsearch\Query();
$result = $query->from('article')->body([
'query' => [
'multi_match' => [
'query' => 'Elasticsearch 教程',
'fields' => ['title^3', 'content'],
'analyzer' => 'ik_smart'
]
]
])->all();
注意:multi_match 的 analyzer 参数在 ES 8.x 中已被移除,必须改用 search_analyzer 在 mapping 中预设,否则报错 unknown field [analyzer]。
为什么 save() 后查不到、或数据格式错乱
这是 Yii + ES 最常踩的坑:ES 文档是 schema-less 的,但 Yii 的 ActiveRecord 会强制校验字段类型,且默认把空数组、null 值转成字符串或丢弃。
-
save()前确保字段值类型与 mapping 一致:比如 mapping 设了"status": {"type": "keyword"},你就不能传整数1,得传字符串'active' - 日期字段必须是 ISO8601 格式字符串(如
'2026-04-19T12:00:00+08:00'),不能传DateTime对象或时间戳 - 嵌套对象字段(如
author.name)需在 mapping 中明确定义为nested类型,且 Yii 层要用ArrayHelper::getValue($data, 'author.name')提取,不能靠魔术方法 - 调试技巧:先用
curl -XPOST 'localhost:9200/article/_doc' -H 'Content-Type: application/json' -d '{...}'手动插入一条,再对比 Yiisave()发出的 JSON 是否一致
真正麻烦的不是配置,而是 mapping 和 PHP 数据结构之间的隐式契约——一旦字段类型或嵌套层级对不上,ES 不报错,只是不索引、不返回,排查起来特别费时间。


















