根本原因是分词器不一致:写入用ik_max_word而查询用默认standard分词器,导致“人工智能”被切为单字而非完整词项;索引mapping和查询match中必须显式声明analyzer为ik_max_word,且esapi.searchrequest必填index、body、context三字段。

直接用 elastic.NewClient() 或 esapi.SearchRequest 发请求,90% 的中文搜索失败、超时、空结果,不是 ES 没数据,而是 Go 客户端配置和查询体写法没对齐 ES 8+ 的硬性要求。
为什么 match 查不到中文?
根本原因是分词器不一致:写入用 ik_max_word,查询却走默认 standard 分词器,“人工智能”被切成了 “人工”“智能”,而 IK 会保留完整词项。
- 索引 mapping 中字段必须显式声明:
"analyzer": "ik_max_word" - 查询时
match必须加"analyzer": "ik_max_word",不能省略 - 别信“自动继承”,ES 不会跨写入/查询自动对齐分词器
- 验证方式:用 Kibana 的
_analyzeAPI 对比同一段文本在两种 analyzer 下的输出
esapi.SearchRequest 必填哪三个字段?
漏一个,请求就废——不是报错,而是返回空 hits 或 no search context found。
-
Index:必须是[]string{"articles"}这种非空切片,不能是""或"*"(生产环境会被拒绝) -
Body:必须是*bytes.Reader,常见错误是json.Marshal()后没包bytes.NewReader(),导致 body 为空,ES 返回400 Bad Request -
Context:必须带超时,例如context.WithTimeout(ctx, 3*time.Second);不设的话 HTTP client 可能卡死在连接池里,goroutine 悬停
怎么避免 panic 和 context deadline exceeded?
panic 和超时几乎都来自客户端初始化和调用链没按 v8+ 规范来。
- 全局复用一个
*elasticsearch.Client实例,别每次请求都new—— 它是线程安全的 - 禁用 sniffing:
Sniff: false,Service Mesh(如 Istio)下自动发现节点必失败 - HTTPS 自签名证书只在测试环境跳过验证:
&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} - 每次调用后必须
defer res.Body.Close(),否则 fd 泄露,跑几天就too many open files
分页超过 10000 条怎么处理?
from/size 到 10000 就硬扛不住,ES 直接报 Result window is too large,这不是性能问题,是设计限制。
- 改用
search_after+sort,按_id或时间戳排序(不能用_score,它不稳定) - 第一次查带
size,返回最后一个文档的sort值,下次请求传给search_after - 注意:
search_after要求sort字段有确定值且非空,比如"created_at"不能为空
最易忽略的其实是 mapping 和 query 的 analyzer 同步——写入和查询用不同分词器,等于在两个平行宇宙里搜,再准的 query 也匹配不上。调试时先确认 analyzer 输出是否一致,再动其他。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











