Yii2集成Elasticsearch需重点解决mapping冲突、查询不命中、高亮失效、批量写入失败四问题:mapping须预创建并固化字段类型;bool查询中确定性条件用filter而非must;高亮字段需在_source中存在且未禁用store;bulk写入需调优batch size与timeout。
直接用 yiisoft/yii2-elasticsearch 扩展就行,但光装包、配节点、建模型远远不够——多数人卡在 mapping 冲突、查询不命中、高亮失效、批量写入失败这四点上。
mapping 定义必须提前固化,不能靠 auto_create
Elasticsearch 的 mapping 一旦写入就不可修改字段类型(比如把 text 改成 keyword),而 Yii 的 ActiveRecord::updateMapping() 只在索引不存在时生效。如果已有数据,调它会报 mapper_parsing_exception。
- 上线前用脚本显式创建索引 + mapping,例如:
PUT /my_index { "settings": { "number_of_shards": 1 }, "mappings": { "properties": { "title": { "type": "text", "analyzer": "ik_smart" }, "status": { "type": "keyword" }, "created_at": { "type": "date" } } } } -
ActiveRecord::index()返回的字符串必须和你手动创建的索引名完全一致(区分大小写) - 中文分词器(如 ik)需提前装好,且 mapping 中
analyzer字段值要和插件注册名匹配,否则title字段搜不出中文
bool 查询里 filter 和 must 别混用
Yii 的 find()->query() 构造 DSL 时,容易把过滤条件全塞进 must,导致性能掉一半——filter 上下文不计算相关度、可缓存,must 会触发评分且无法缓存。
- 状态、时间范围、ID 等确定性条件,一律走
filter:$query = [ 'bool' => [ 'must' => [['match' => ['title' => 'yii']]], 'filter' => [ ['term' => ['status' => 'active']], ['range' => ['created_at' => ['gte' => '2025-01-01']]] ] ] ]; - 用
yii\elasticsearch\Query::addFilter()比手拼数组更安全,它自动归入filter分支 - 别在
filter里用match或wildcard,它们不支持 filter 上下文,会静默降级为must
高亮字段必须在 source 里存在且未禁用
调 highlight() 后返回空数组?大概率是字段没进 _source,或者 mapping 里关了 "store": true。
云雀语言模型
云雀是一款由字节跳动研发的语言模型,通过便捷的自然语言交互,能够高效的完成互动对话
下载
- 确认 mapping 中目标字段(如
title)没有设置"store": false - 查询时显式指定
_source字段,避免被全局"_source": false配置拦截:'_source' => ['title', 'descr']
- 高亮参数必须用字段原始名,不能用 alias;若用了
fields映射,高亮只对原始字段生效 - ik 分词器下,
highlight的fragment_size建议设为 100+,太小会导致中文断字
bulk 写入失败常因 batch size 或 timeout 不匹配
batchInsert() 报 cURL error 52: Empty reply from server 或超时,不是网络问题,而是 ES 默认单次 bulk 请求限制为 10MB、1000 条,而 Yii 默认每批发 100 条但没设超时。
- 在连接配置里加
'options' => ['timeout' => 30],避免大文档批量卡住 - 手动控制批次:用
array_chunk($data, 50)切分,比默认 100 更稳(尤其含大 text 字段时) - bulk 失败后,
yii\elasticsearch\Exception的$exception->response里有具体哪条 document 出错,别只看 HTTP 状态码 - 别在事务里嵌套 bulk —— ES 本身无事务,Yii 的 DB 事务对 ES 无效
最麻烦的永远不是“怎么连上”,而是 mapping 和 query 语义的隐式耦合:同一个字段在 mapping 里是 text,查询却用 term;或者开了 fielddata 却忘了给 keyword 字段配 doc_values: true。这些细节不验证,线上就只能靠 GET /my_index/_search?q=* 一行行试。