必须用官方v8客户端+单例注册+显式mapping,禁用dynamic mapping和裸cURL;需设timeout≤5秒、retries=3、IK分词器与ES版本严格对齐,并接受ES近实时特性导致的1秒搜索延迟。

Webman 集成 Elasticsearch 想稳定跑起来,必须绕开「连得上但搜不到」「写入成功却查为空」「一并发就 429」这三类高频故障点。直接用官方 elasticsearch/elasticsearch v8 客户端 + 单例注册 + 显式 mapping 是当前最可控的路径。
为什么不能用 webman-search 插件快速起步
插件对新手友好,但会掩盖底层细节,导致后续踩坑更难定位。比如它默认启用 dynamic mapping,中文字段自动被识别为 text 类型却没配 ik_max_word 分词器,结果 match 查询永远分不出词;又比如它把 search() 封装成链式调用,但内部没加 filter 上下文,高并发下 CPU 突增;再比如它不处理 search_after,数据量一过万,from/size 分页直接超时。
这些不是插件缺陷,而是设计取舍:它面向「能跑通」,不是「能压测」。如果你的业务要支撑每秒数百次搜索、千万级文档、中文高亮+同义词+拼写纠错,就得直面客户端和 mapping。
客户端必须注册为单例并显式设 timeout 和 retries
Webman 是常驻内存的 Swoole 应用,每次请求都 new 一个 ClientBuilder 会导致连接池失效、TCP 句柄耗尽、协程阻塞——这不是 ES 不行,是客户端没管住生命周期。
- 在
config/container.php中注册单例,不要在控制器里临时构建 - 必须调用
setConnectionParams(['timeout' => 5.0, 'connect_timeout' => 3.0]),v8 默认 30 秒超时会卡死整个 worker - 必须设
setRetries(3),否则遇到429 Too Many Requests或503 Service Unavailable直接失败,不退避 - Docker 环境下 hosts 写
http://elasticsearch:9200,别写localhost,否则 DNS 解析失败静默断连
中文搜不到?八成是 mapping 没硬编码分词器
ES 默认的 standard 分词器对中文无效,不会按词切分,“搜索引擎”会被切成“搜”“索”“引”“擎”四个字,导致无法召回。动态 mapping 不会自动识别中文并装 IK,必须在建索引时显式声明。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
创建索引时 body 必须包含:
'settings' => [
'analysis' => [
'analyzer' => [
'ik_analyzer' => [
'type' => 'custom',
'tokenizer' => 'ik_max_word'
]
]
]
],
'mappings' => [
'properties' => [
'title' => ['type' => 'text', 'analyzer' => 'ik_analyzer'],
'content' => ['type' => 'text', 'analyzer' => 'ik_analyzer']
]
]
注意:ik_max_word 和 ES 服务端版本必须严格对齐(如 ES 8.15.1 就只能装 elasticsearch-analysis-ik-8.15.1),差一个小版本就报 406 Not Acceptable。
写入后立刻搜不到?这是正常表现,不是 bug
client->index() 返回成功 ≠ 文档已可搜索。ES 默认 refresh_interval 是 1 秒,数据先进内存 buffer,需 refresh 后才生成可搜索 segment。你用 GET /my_index/_doc/1 能查到,但 search 返回空,就是这个原因。
- 开发时可用
POST /my_index/_refresh强制刷新,但仅限本地调试 - 生产环境禁止频繁调用
_refresh,会生成大量小 segment,拖慢 merge 和查询 - 业务上应接受「最多 1 秒延迟」,这是 ES 近实时(NRT)的固有特性
- 若强一致性要求高(如订单状态页),关键字段仍应以 MySQL 为准,ES 只做非核心检索
真正容易被忽略的是:mapping 字段类型一旦设错(比如该用 text 却写了 keyword),后续无法直接修改,只能重建索引——所以建索引前务必验证分词效果:POST /my_index/_analyze?analyzer=ik_max_word。


















