结论先行

直接用 Golang 模拟 HTTP 请求访问 Elasticsearch 最方便了!(官方的 SDK 就是类似的做法)

前言

因工作需要,要定期从 Elasticsearch(以下简称es)中取数据。我选的编程语言是 Golang,下面讲一下我自己在用 Golang 查询 es 数据的时候遇到的坑。

注意事项

1. Golang操作Elasticsearch引用的SDK

主流的SDK有两种

  • github.com/olivere/elastic (第三方)
  • github.com/elastic/go-elasticsearch (官方)

一般来说,官方的 SDK 最好的,因为支持性是最强的,所以我一般都用官方给的 SDK。但第三方SDK还是很火,所以这次我来试试看。(从体验结果上来说,还是官方的好用)

2. SDK版本和Elasticsearch版本要对齐

如果不对齐,使用 SDK 向 es 请求的时候就会报错。一般 SDK 和 es 的版本号是相同的,例如5.x、6.x、7.x。

如果不知道目标 es 的版本是多少,可以直接在 es 里面查一下。

curl http://es_ip:port

{
 "name" : "node-1",
 "cluster_name" : "elasticsearch",
 "cluster_uuid" : "",
 "version" : {
   "number" : "7.13.1",
   "build_flavor" : "default",
   "build_type" : "tar",
   "build_hash" : "",
   "build_date" : "2021-05-28T17:40:59.346932922Z",
   "build_snapshot" : false,
   "lucene_version" : "8.8.2",
   "minimum_wire_compatibility_version" : "6.8.0",
   "minimum_index_compatibility_version" : "6.0.0-beta1"
},
 "tagline" : "You Know, for Search"
}

我这个测试环境里面的 es 版本就是7.13.1,然后下载对应的 SDK 就行了。

3. 创建Elasticsearch客户端失败

有人在创建 es 客户端的时候会遇到这个报错。

context deadline exceeded

这是因为 github.com/olivere/elastic 这个包会自动转换连接地址,所以需要设置 elastic.SetSniff 为 false。

// 创建client连接ES
client, err := elastic.NewClient(
   elastic.SetURL(esUrl),
 elastic.SetBasicAuth(esId, esKey),
 // 这里设置成不需要地址自动转换,否则会报错context deadline exceeded
 elastic.SetSniff(false),
)

4. Elasticsearch查询结果的数据格式转换

使用 Golang 给 es 做查询是这样的。

response, err := client.Get().
Index(index).Type(type).
Id(id).
Do(context.Background())

但是这个 response 的数据格式是 *GetService,并且查询到的数据是在 response.Source 中。而这个 response.Source 的数据结构是 *json.RawMessage,这是一种原始的 json 结构,不能直接读。但毕竟算是 json,所以可以用一个数据结构把这个 json 里面的需要的数据映射出来。

type Data struct {
Name string `json:"name"`
Age string `json:"age"`
}

func GetData(client *elastic.Client, index string) {
 res, err := client.Get().Index(index).Type("_doc").Id("userTotal-2021-10-14").Do(context.Background())
if err != nil {
fmt.Println("查询数据错误")
return
}

if res.Found {
var msg ProxyData
// 这里别忘了*,因为res.Source是地址
    if err := json.Unmarshal(*res.Source, &msg); err != nil {
fmt.Println("转换成json失败")
        return
}
fmt.Println(msg)
}
}
直接用HTTP请求访问Elasticsearch

就我目前三种 Golang 操作 es 的方式(官方 SDK、第三方 SDK、直接HTTP请求)使用下来,最方便的其实还是直接用 HTTP 请求直接访问。因为使用 HTTP 直接访问可以直接用 es 的查询语法,而不需要去学习 SDK 的逻辑。第二方便的就是官方的 SDK,现在最新的官网上也可以直接用 es 的语法,而不用研究 SDK 的具体使用方法。最后才是第三方包。

我有之前自己封装好的 HTTP 请求的代码,而且这种对 es 的操作是绝大部分情况是不需要 tcp 去保持连接的。所以对于我来说,Golang 直接通过 HTTP 请求 es 是最好用的。