推荐安装官方 elasticsearch/elasticsearch 客户端(^8.0 版本),配置 https、禁用证书验证(开发环境)及 basic auth 认证,并在模型中实现 tosearchablearray() 方法映射字段,搜索后通过 id 列表查库关联模型。

怎么装 laravel 和 Elasticsearch 的连接包
Laravel 本身不内置 Elasticsearch 支持,得靠第三方包。目前最稳定、维护活跃的是 laravel/scout + algolia/algoliasearch-client-php 这套组合——但注意:Algolia 不是 Elasticsearch。真要用 ES,必须换驱动。
主流选择是 elasticquent/elasticquent 或直接用官方 elasticsearch/elasticsearch 客户端 + 自己封装。前者已多年未更新(最后一次 commit 是 2021),PHP 8.1+ 会报错;后者更可控,也更贴近实际项目需求。
-
composer require elasticsearch/elasticsearch是唯一推荐的安装方式 - 别装
laravel/scout-elasticsearch-driver这类非官方驱动,多数只支持旧版 ES(6.x),且对 ES 8.x 的 API 变更(如移除 type、强制 https、Basic Auth 改为 API key)完全没适配 - 如果用 Laravel 10+,确保 PHP 版本 ≥ 8.1,客户端版本选
^8.0(对应 ES 8.x),别用^7.0(那是给 ES 7.17 用的)
ES 8.x 连接失败常见报错和修复
连不上不是配置写错了,大概率是 ES 8 默认关掉了 HTTP 接口或认证没过。典型错误:
-
curl Error 60: ssl certificate problem:ES 8 启动默认启用 HTTPS,但本地开发用自签名证书,PHP cURL 拒绝验证 -
Unauthorized:ES 8 关闭了匿名访问,必须带认证凭据 -
No alive nodes found in your cluster:地址写成<a href="https://www.php.cn/link/fb7850115a917d3ab720269da3e667de">https://www.php.cn/link/fb7850115a917d3ab720269da3e667de</a>,但实际服务跑在<a href="https://www.php.cn/link/02c1ffbf4378893da347eb8ec50b2456">https://www.php.cn/link/02c1ffbf4378893da347eb8ec50b2456</a>
解决方法:
- 在 config/services.php 加配置时,
host必须带协议,比如'host' => '<a href="https://www.php.cn/link/02c1ffbf4378893da347eb8ec50b2456">https://www.php.cn/link/02c1ffbf4378893da347eb8ec50b2456</a>' - 开启
verify_certs => false(仅开发环境),否则要导出 CA 证书并指定cafile路径 - 认证用
basic_authentication数组传['username' => 'elastic', 'password' => 'xxx'],别用 header 手动拼
// config/services.php 'es' => [ 'hosts' => ['https://www.php.cn/link/02c1ffbf4378893da347eb8ec50b2456'], 'basic_authentication' => [ 'username' => 'elastic', 'password' => env('ES_PASSWORD'), ], 'ssl' => ['verify_peer' => false, 'verify_host' => false], ],
怎么在 Laravel 模型里映射 ES 索引字段
Elasticsearch 不认 Eloquent 的 $fillable 或 casts,字段类型得手动对齐。比如数据库里是 json 字段,ES 里得设成 text 或 keyword,否则搜索会失效。
- 别直接用
toArray()推数据进 ES:时间字段可能变成字符串,numeric 类型被当 text 处理 - 创建索引前先调
PUT /my_index手动定义 mapping,尤其注意:date字段必须显式声明 format,否则 ES 8 会拒收非 ISO 格式时间 - Laravel 模型里加个
toSearchableArray()方法,把 carbon 实例转成$date->toISOString(),把布尔值转(int),避免 ES 自动识别出错
public function toSearchableArray() { return [ 'id' => $this->id, 'title' => $this->title, 'published_at' => $this->published_at?->toISOString(), 'is_active' => (int) $this->is_active, ]; }
搜索结果怎么和 Eloquent 模型关联起来
ES 返回的是纯数组,没有模型实例,也不能直接用 with() 预加载关系。常见做法是搜出 ID 列表,再用 whereIn() 查库。
- 别用
Model::hydrate($hits):ES 返回结构和数据库字段名不一致(比如_source套一层),会漏数据 - 搜索返回的
_id是字符串,数据库主键可能是 int,查库前记得array_map('intval', $ids) - 如果 ID 数量超 1000,
whereIn可能触发 mysql 的 max_allowed_packet 或性能下降,这时得用 chunk 查询
$esResponse = $client->search([...]); $ids = array_column($esResponse['hits']['hits'], '_id'); $models = Post::whereIn('id', array_map('intval', $ids))->get();
ES 的排序、高亮、聚合这些功能,Laravel 层没法代理,得自己解析 highlight 或 aggregations 字段。这部分逻辑一旦写死在控制器里,后续改搜索策略就容易散落各处——建议单独抽个 SearchService 类管住。