Elasticsearch Go语言客户端go-elasticsearch入门
📅 2021-05-22 | 🖱️7,522
go-elasticsearch
是ES官方提供的Go语言客户端。本文将结合ES 7.12对这个库做一个基本入门使用的演示。
1.开发环境准备 #
创建一个空的项目,并使用go moudles引入go-elasticsearch
的依赖:
1mkdir go-es-showcase
2cd go-es-showcase
3go mod init go-es-showcase
4export GOPROXY="https://goproxy.io"
5go get github.com/elastic/go-elasticsearch/v7@v7.12.0
6go get github.com/stretchr/testify
这里基于go testing单元测试编码风格来演示对go-elasticsearch
这个库的使用。
首先在项目的根目录下创建一个名称为go_esclient_test.go
,并演示一下如何创建客户端:
1package main
2
3import (
4 "testing"
5
6 es "github.com/elastic/go-elasticsearch/v7"
7 "github.com/stretchr/testify/assert"
8)
9
10var (
11 client *es.Client
12)
13
14func init() {
15 var err error
16 client, err = es.NewClient(es.Config{
17 Addresses: []string{"http://localhost:9200"},
18 Username: "username",
19 Password: "password",
20 })
21 if err != nil {
22 log.Fatal(err)
23 }
24}
25
26func TestNewESClient(t *testing.T) {
27 t.Log(client.Info())
28}
2.索引的创建、修改和删除 #
创建索引:
1func TestCreateIndex(t *testing.T) {
2 a := assert.New(t)
3 response, err := client.Indices.Create("book-0.1.0", client.Indices.Create.WithBody(strings.NewReader(`
4 {
5 "aliases": {
6 "book":{}
7 },
8 "settings": {
9 "analysis": {
10 "normalizer": {
11 "lowercase": {
12 "type": "custom",
13 "char_filter": [],
14 "filter": ["lowercase"]
15 }
16 }
17 }
18 },
19 "mappings": {
20 "properties": {
21 "name": {
22 "type": "keyword",
23 "normalizer": "lowercase"
24 },
25 "price": {
26 "type": "double"
27 },
28 "summary": {
29 "type": "text",
30 "analyzer": "ik_max_word"
31 },
32 "author": {
33 "type": "keyword"
34 },
35 "pubDate": {
36 "type": "date"
37 },
38 "pages": {
39 "type": "integer"
40 }
41 }
42 }
43 }
44 `)))
45 a.Nil(err)
46 t.Log(response)
47}
查看索引信息:
1func TestGetIndex(t *testing.T) {
2 a := assert.New(t)
3 response, err := client.Indices.Get([]string{"book"})
4 a.Nil(err)
5 t.Log(response)
6}
删除索引:
1func TestDeleteIndex(t *testing.T) {
2 a := assert.New(t)
3 response, err := client.Indices.Delete([]string{"book-0.1.0"})
4 a.Nil(err)
5 t.Log(response)
6}
3.文档的创建、修改和删除 #
创建文档:
1type Book struct {
2 Author string `json:"author"`
3 Name string `json:"name"`
4 Pages int `json:"pages"`
5 Price float64 `json:"price"`
6 PubDate *time.Time `json:"pubDate"`
7 Summary string `json:"summary"`
8}
9
10func TestCreateDocument(t *testing.T) {
11 a := assert.New(t)
12 body := &bytes.Buffer{}
13 pubDate := time.Now()
14 err := json.NewEncoder(body).Encode(&Book{
15 Author: "金庸",
16 Price: 96.0,
17 Name: "天龙八部",
18 Pages: 1978,
19 PubDate: &pubDate,
20 Summary: "...",
21 })
22 a.Nil(err)
23 response, err := client.Create("book", "10001", body)
24 a.Nil(err)
25 t.Log(response)
26}
覆盖性更新文档,如果给定的文档ID不存在,将创建文档:
1func TestIndexDocument(t *testing.T) {
2 a := assert.New(t)
3 body := &bytes.Buffer{}
4 pubDate := time.Now()
5 err := json.NewEncoder(body).Encode(&Book{
6 Author: "金庸",
7 Price: 96.0,
8 Name: "天龙八部",
9 Pages: 1978,
10 PubDate: &pubDate,
11 Summary: "...",
12 })
13 a.Nil(err)
14 response, err := client.Index("book", body, client.Index.WithDocumentID("10001"))
15 a.Nil(err)
16 t.Log(response)
17}
局部性更新文档,下面的代码借助go json的omitempty
,在将更新数据对象序列化成json,可以只序列化非零值字段,实现局部更新。
实际项目采用这种方式时,需要注意某个字段的零值具有业务意义时,可以采用对应的指针类型实现。
1type doc struct {
2 Doc interface{} `json:"doc"`
3}
4
5type Book struct {
6 Author string `json:"author,omitempty"`
7 Name string `json:"name,omitempty"`
8 Pages int `json:"pages,omitempty"`
9 Price float64 `json:"price,omitempty"`
10 PubDate *time.Time `json:"pubDate,omitempty"`
11 Summary string `json:"summary,omitempty"`
12}
13
14func TestPartialUpdateDocument(t *testing.T) {
15 a := assert.New(t)
16 body := &bytes.Buffer{}
17 err := json.NewEncoder(body).Encode(&doc{
18 Doc: &Book{
19 Name: "《天龙八部》",
20 },
21 })
22 a.Nil(err)
23 response, err := client.Update("book", "10001", body)
24 a.Nil(err)
25 t.Log(response)
26}
删除文档:
1func TestDeleteDocument(t *testing.T) {
2 a := assert.New(t)
3 response, err := client.Delete("book", "10001")
4 a.Nil(err)
5 t.Log(response)
6}
获取文档:
1func TestGetDocument(t *testing.T) {
2 a := assert.New(t)
3 response, err := client.Get("book", "10001")
4 a.Nil(err)
5 t.Log(response)
6}
4.文档的批量创建和删除 #
批量操作对应ES的REST API是:
1POST /<target>/_bulk
2{ "index" : { "_id" : "1" } }
3{ "field1" : "value1" }
4{ "delete" : { "_id" : "2" } }
5{ "create" : { "_id" : "3" } }
6{ "field1" : "value3" }
7{ "update" : {"_id" : "1" } }
8{ "doc" : {"field2" : "value2"} }
对应index
, create
, update
操作,提交的数据都是由两行组成,第一行是meta数据,描述操作信息,第二行是具体提交的数据,对于delete操作只有一行meta数据。
对照REST API,在go client的示例代码如下:
1func TestBulk(t *testing.T) {
2 createBooks := []*Book{
3 {
4 ID: "10002",
5 Name: "神雕侠侣",
6 Author: "金庸",
7 },
8 {
9 ID: "10003",
10 Name: "射雕英雄传",
11 Author: "金庸",
12 },
13 }
14 deleteBookIds := []string{"10001"}
15
16 a := assert.New(t)
17 body := &bytes.Buffer{}
18 for _, book := range createBooks {
19 meta := []byte(fmt.Sprintf(`{ "index" : { "_id" : "%s" } }%s`, book.ID, "\n"))
20 data, err := json.Marshal(book)
21 a.Nil(err)
22 data = append(data, "\n"...)
23 body.Grow(len(meta) + len(data))
24 body.Write(meta)
25 body.Write(data)
26 }
27 for _, id := range deleteBookIds {
28 meta := []byte(fmt.Sprintf(`{ "delete" : { "_id" : "%s" } }%s`, id, "\n"))
29 body.Grow(len(meta))
30 body.Write(meta)
31 }
32 t.Log(body.String())
33
34 response, err := client.Bulk(body, client.Bulk.WithIndex("book"))
35 a.Nil(err)
36 t.Log(response)
37}
5.文档搜索 #
下面代码演示了go-elasticsearch
提供的搜索查询功能,实际中查询请求体建议使用go template动态生成。
1func TestSearch(t *testing.T) {
2 a := assert.New(t)
3 body := &bytes.Buffer{}
4 body.WriteString(`
5 {
6 "_source":{
7 "excludes": ["author"]
8 },
9 "query": {
10 "match_phrase": {
11 "author": "古龙"
12 }
13 },
14 "sort": [
15 {
16 "pages": {
17 "order": "desc"
18 }
19 }
20 ],
21 "from": 0,
22 "size": 5
23 }
24 `)
25 response, err := client.Search(client.Search.WithIndex("book"), client.Search.WithBody(body))
26 a.Nil(err)
27 t.Log(response)
28}