先确认Elasticsearch控制台命令是否注册:检查console/config/main.php中controllerMap是否配置'elasticsearch' => 'app\commands\ElasticsearchController',且类继承yii\console\Controller、路径正确;重建索引必须加--delete-then-create=1避免数据混杂;bulk写入需调小batch-size、延长timeout、流式读取;mapping须显式定义关键字段类型及format,不一致需删索引重建。

yii elasticsearch rebuild index 命令没反应?先确认是否注册了 Elasticsearch 控制台命令
Yii 应用里跑 php yii elasticsearch/rebuild-index 报错“Unknown command”或直接忽略,大概率是命令类没被 Console Application 扫描到。Yii2 的 console 配置和 web 配置默认是分开的,ElasticsearchController 类即使写了,也不会自动生效。
- 检查
console/config/main.php中'controllerMap'是否包含类似'elasticsearch' => 'app\commands\ElasticsearchController' - 确保该 Controller 继承自
\yii\console\Controller,不是\yii\web\Controller - 路径别写错:比如
app\commands\ElasticsearchController对应文件必须在@app/commands/ElasticsearchController.php - 如果用了命名空间别名(如
use app\commands\ElasticsearchController;),注意controllerMap里填的是完整类名字符串,不是 use 后的简写
rebuild-index 过程中数据丢失?别跳过 --delete-then-create 参数
很多自定义的 rebuild-index 命令实现里,默认只是调用 PUT /index-name 创建索引、再 bulk 写入,但旧索引不会自动删——结果新旧数据混在一起,查出来重复或缺失。
- 强制删除旧索引再重建,必须显式加
--delete-then-create=1(或-d,取决于你命令的定义) - 不加这个参数,ES 会尝试在已有索引上写入,而 mapping 不兼容时 bulk 会静默失败,只报几条
400 Bad Request错误在日志里 - 生产环境执行前,建议先用
curl -XGET 'http://localhost:9200/_cat/indices?v'确认目标索引名是否存在、状态是否 yellow/green - 如果索引名带时间戳(如
user_202405),重建逻辑里要动态生成,不能硬编码
bulk 写入卡住或超时?调整 batch-size 和 connection timeout
从 MySQL 或 ActiveRecord 拉几十万条数据进 ES,用默认 batch-size=100 + 默认 HTTP 超时,很容易在中间断掉,报 cURL error 28: Operation timed out 或 Connection refused。
- 降低单次 bulk 大小:
--batch-size=50(尤其字段多、有 nested 类型时) - 延长客户端超时:
Elasticsearch::setHttpClientOptions(['timeout' => 60]),这个得在 Controller 的beforeAction()或初始化阶段设 - 避免用
ActiveRecord::find()->each()直接喂给 bulk——它会反复查数据库,内存涨得快;改用createCommand()->batch(1000)流式读取 - ES 服务端也要检查:
http.max_content_length(默认 100mb),太小会导致 bulk 请求被拒,错误信息是"Content-Length header too long"
索引 mapping 不一致导致写入失败?别依赖自动 mapping
第一次建索引时没定义 mapping,ES 自动推导了 date 字段为 text,后面数据里出现 "2024-05-20" 就会 bulk 失败,报 failed to parse field [created_at] of type [date]。
- 所有关键字段(尤其是
date、integer、boolean、nested)必须在createIndex()时显式声明 mapping,不要靠 dynamic mapping - mapping 定义里,
"type": "date"必须配"format",比如"format": "strict_date_optional_time||epoch_millis" - 如果用 Yii 的
yii\elasticsearch\Connection::getMapping()获取结构,注意它返回的是数组,不是 JSON 字符串,别直接json_encode丢给 ES API - 开发期可加个校验步骤:重建前先
GET /index-name/_mapping和本地 mapping 数组 diff 一下,不一致就 abort
mapping 一旦创建就不能改字段类型,删索引是唯一办法——所以第一次写错,后面每次 rebuild 都得删,这点容易被当成“命令问题”,其实是设计漏了。










