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