必须使用elastic/go-elasticsearch/v9对接ES 8.0+,因olivere/elastic/v7已归档且协议不兼容,会导致400/406错误;esapi.SearchRequest需显式设置Index、Body、Context三字段,多维搜索须用bool组合must/filter/must_not等子句。

新项目必须用 elastic/go-elasticsearch/v9,别碰 olivere/elastic/v7 —— 它已归档,连不上 ES 8.0+ 不是代码写错了,是协议断层直接被拒。
选错客户端版本导致 400/406 错误
ES 8.0+ 默认禁用 _type、强制 HTTPS、改了 /_search 路径和 Authorization header 格式。olivere/elastic/v7 还按 7.x 协议拼 URL 和 body,一发请求就被拒绝。
- 典型错误:HTTP 状态码
400 Bad Request(body 解析失败)或406 Not Acceptable(Acceptheader 不匹配) - 不是认证失败或超时,而是协议不兼容——ES 根本没进 query 处理流程
- ES 7.10–7.17 可用
olivere/elastic/v7;但只要装的是 8.15 或 9.0 alpha,就必须切到elastic/go-elasticsearch/v9 - 同一项目混用两个客户端 →
context.Context传参冲突、http.RoundTripper复用异常,可能静默超时
esapi.SearchRequest 必须显式设三个字段
官方客户端不补默认值,漏一个就返回空 hits 或 panic。最常漏的是:
-
Index:不能传""或"*";生产环境禁止通配符,ES 可能拒收或打满慢日志 -
Body:必须是*bytes.Reader;json.Marshal()后得套bytes.NewReader();传map[string]interface{}会编译失败,传 raw string 容易引号嵌套出错 -
Context:必须带超时,如context.WithTimeout(ctx, 3*time.Second);不设的话 HTTP client 可能卡死在连接池,goroutine 悬停
正确示例:
立即学习“go语言免费学习笔记(深入)”;
req := esapi.SearchRequest{
Index: []string{"blogs"},
Body: bytes.NewReader([]byte(`{"query":{"match":{"title":"golang"}}}`)),
Context: context.WithTimeout(ctx, 3*time.Second),
}
res, err := req.Do(ctx, es)
查不到结果?先盯住分词器、refresh 和字段类型
90% 的“搜不到”不是 query 写错,而是索引侧配置和写入行为不一致:
- 中文分词:索引用了
ik_max_word,但查询没加"analyzer": "ik_max_word",ES 默认用standard分词,“人工智能”被切成“人工”“智能”,自然匹配不上 - refresh 延迟:文档写入后默认 1 秒才可搜索;刚
Index完立刻Search,必然为空;开发期可临时加Refresh: "true",但批量导入时严禁使用 - 字段类型错配:mapping 里
title是keyword,你却用match查——keyword不分词,match查不了;该用term查询
多维度搜索要组合 bool + range + terms + must_not
ES 的多维检索本质是布尔逻辑嵌套,不是 SQL 的 WHERE a AND b AND c 那种线性拼接:
-
must:全部满足(相当于 AND) -
should:至少满足一个(相当于 OR),但需配合minimum_should_match -
filter:不参与算分、可缓存,适合range、terms、exists等结构化条件 -
must_not:排除项,注意它不支持text字段的全文否定(要用bool+must+must_not套match_phrase等精确子句)
示例(查标题含“Go”、价格在 50–200、分类为 “backend” 或 “devops”、且非草稿状态):
`{
"query": {
"bool": {
"must": [
{"match": {"title": "Go"}},
{"terms": {"category": ["backend", "devops"]}}
],
"filter": [
{"range": {"price": {"gte": 50, "lte": 200}}},
{"term": {"status": "published"}}
]
}
}
}`
注意:filter 里的 terms 和 range 必须对应 mapping 中字段类型(比如 category 得是 keyword,price 得是 float 或 integer),否则整个查询返回空。


















