连不上ES主因是客户端版本过时或Transport配置错误:需用elastic/go-elasticsearch/v9、显式设Addresses、禁用Healthcheck、设Transport超时;SearchRequest必填Index、Body(bytes.Reader)、Context;DSL要匹配字段类型,Source解析须用hit.Source方法。

连不上 ES?先看客户端版本和 Transport 配置
ES 8.x 或 9.x 集群根本连不上,不是网络问题,大概率是用了已归档的 olivere/elastic/v7。它不发 Content-Type: application/json,也不走 HTTPS,默认被 ES 8+ 拒绝,返回 406 Not Acceptable 或静默空响应。
新项目必须用 github.com/elastic/go-elasticsearch/v9(或 v8),安装命令:go get github.com/elastic/go-elasticsearch/v9。
- 初始化 client 时必须显式传
elasticsearch.Config{Addresses: []string{"https://es.example.com:9200"}},漏掉Addresses会 panic - ES 启了 HTTPS 但证书不可信?加
Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} - 别开
Healthcheck: true——默认健康检查会阻塞初始化,尤其 K8s 环境里 ES 还没 ready 就卡住;自己做重试更可控 - 超时必须设:
Transport: &http.Transport{Timeout: 5 * time.Second},否则默认无限等待,goroutine 悬停
SearchRequest 空结果?三个字段缺一不可
esapi.SearchRequest 不补默认值,漏一个就返回空 hits,且不报错。常见写法看似合法,实则发的是废请求。
-
Index:不能为""或"*";生产环境 ES 会拒收通配符,必须明确写成[]string{"blogs"} -
Body:必须是*bytes.Reader;json.Marshal()后得包一层bytes.NewReader(),传 raw string 或 map 会编译失败或400 -
Context:必须带超时,如context.WithTimeout(ctx, 3*time.Second);不设就可能卡在连接池,整个 goroutine 挂起
正确示例:
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
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)全文搜 vs 精确查:MatchQuery 和 TermQuery 别混用
DSL 语法合法,但查不到数据——ES 不报错,只静默返回空 hits。
-
MatchQuery("title", "golang tutorial"),它走 analyzer,适合text类型字段 - 精确匹配(
status、category、ID)必须用TermQuery("status", "published"),MatchQuery对 keyword 字段无效 - 组合条件优先用
BoolQuery().Must().Filter():Must放全文搜(参与算分),Filter放状态/范围(不打分、缓存友好、性能更好) - 时间范围别拼字符串:
RangeQuery("created_at").Gte("now-7d").Lte("now"),ES 原生支持now-7d/d这类表达式
解析 hit.Source 时最容易 panic
ES 返回的文档内容在 hit._source 字段下,不是顶层 JSON;直接 json.Unmarshal(raw, &MyDoc{}) 会失败或字段为空。
正确做法是调 hit.Source 方法:err := json.Unmarshal(*hit.Source, &doc),注意 *hit.Source 是指针。
字段名必须和 mapping 完全一致:user_id ≠ userId,查不到不会提示,只会返回空切片。
中文搜不到?先盯住分词器、refresh 和字段类型:索引用了 ik_max_word,但查询 DSL 没加 "analyzer": "ik_max_word",ES 默认走 standard 分词器;title 字段 mapping 是 keyword,却用 MatchQuery 查——该用 TermQuery。

















