本教程从go语言角度讲解如何对elasticsearch进行增删改查。
目前golang操作elasticsearch的第三方包中最流行的是:
https://github.com/olivere/elastic
本教程也是基于elastic开发包进行讲解。
版本说明
golang的elastic开发包和elasticsearch版本有一些对应关系,在开发前需要注意下,必须选择正确的版本,下面是golang elastic开发包和elasticsearch版本关系表:
Elasticsearch version | Go Elastic version | go开发包地址 |
7.x | 7.0 | github.com/olivere/elastic/v7 |
6.x | 6.0 | github.com/olivere/elastic |
5.x | 5.0 | gopkg.in/olivere/elastic.v5 |
例如:ES版本是7.0以后的版本,就使用github.com/olivere/elastic/v7这个包地址。
安装依赖包
本教程ES使用的是7.0以后的版本,因此安装GO的依赖包如下
go get github.com/olivere/elastic/v7
提示:如果使用goland作为ide,直接导入 import "github.com/olivere/elastic/v7" 包,goland会自动安装依赖包。
创建ES客户端
在操作ES之前需要创建一个client,用于操作ES,在创建client的时候需要提供ES连接参数。
package main
import "fmt"
import "github.com/olivere/elastic/v7"
func main() {
// 创建ES client用于后续操作ES
client, err := elastic.NewClient(
// 设置ES服务地址,支持多个地址
elastic.SetURL("http://127.0.0.1:9200", "http://127.0.0.1:9201"),
// 设置基于http base auth验证的账号和密码
elastic.SetBasicAuth("user", "secret"))
if err != nil {
// Handle error
fmt.Printf("连接失败: %v\n", err)
} else {
fmt.Println("连接成功")
}
}
创建索引
package main
import (
"context"
"fmt"
"github.com/olivere/elastic/v7"
)
// 索引mapping定义,这里仿微博消息结构定义
const mapping = `
{
"mappings": {
"properties": {
"user": {
"type": "keyword"
},
"message": {
"type": "text"
},
"image": {
"type": "keyword"
},
"created": {
"type": "date"
},
"tags": {
"type": "keyword"
},
"location": {
"type": "geo_point"
},
"suggest_field": {
"type": "completion"
}
}
}
}`
func main() {
// 创建client
client, err := elastic.NewClient(
elastic.SetURL("http://127.0.0.1:9200", "http://127.0.0.1:9201"),
elastic.SetBasicAuth("user", "secret"))
if err != nil {
// Handle error
fmt.Printf("连接失败: %v\n", err)
} else {
fmt.Println("连接成功")
}
// 执行ES请求需要提供一个上下文对象
ctx := context.Background()
// 首先检测下weibo索引是否存在
exists, err := client.IndexExists("weibo").Do(ctx)
if err != nil {
// Handle error
panic(err)
}
if !exists {
// weibo索引不存在,则创建一个
_, err := client.CreateIndex("weibo").BodyString(mapping).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
}
}
提示:后续代码不再提重复提供完整的代码,直接引用client对象,则假定你已经完成包的加载和初始化client对象。
插入一条数据
先定义微博的struct, 跟前面创建的weibo索引结构一一对应。
type Weibo struct {
User string `json:"user"` // 用户
Message string `json:"message"` // 微博内容
Retweets int `json:"retweets"` // 转发数
Image string `json:"image,omitempty"` // 图片
Created time.Time `json:"created,omitempty"` // 创建时间
Tags []string `json:"tags,omitempty"` // 标签
Location string `json:"location,omitempty"` //位置
Suggest *elastic.SuggestField `json:"suggest_field,omitempty"`
}
上面struct定义的时候,都定义了json结构,因为ES请求使用的是json格式,在发送ES请求的时候,会自动转换成json格式。
使用struct结构插入一条ES文档数据,
// 创建创建一条微博
msg1 := Weibo{User: "olivere", Message: "打酱油的一天", Retweets: 0}
// 使用client创建一个新的文档
put1, err := client.Index().
Index("weibo"). // 设置索引名称
Id("1"). // 设置文档id
BodyJson(msg1). // 指定前面声明的微博内容
Do(ctx) // 执行请求,需要传入一个上下文对象
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)
查询数据
// 根据id查询文档
get1, err := client.Get().
Index("weibo"). // 指定索引名
Id("1"). // 设置文档id
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
if get1.Found {
fmt.Printf("文档id=%s 版本号=%d 索引名=%s\n", get1.Id, get1.Version, get1.Index)
}
# 手动将文档内容转换成go struct对象
msg2 := Weibo{}
// 提取文档内容,原始类型是json数据
data, _ := get1.Source.MarshalJSON()
// 将json转成struct结果
json.Unmarshal(data, &msg2)
// 打印结果
fmt.Println(msg2.Message)
更新数据
根据文档id更新内容
_, err := client.Update().
Index("weibo"). // 设置索引名
Id("1"). // 文档id
Doc(map[string]interface{}{"retweets": 0}). // 更新retweets=0,支持传入键值结构
Do(ctx) // 执行ES查询
if err != nil {
// Handle error
panic(err)
}
删除数据
// 根据id删除一条数据
_, err := client.Delete().
Index("weibo").
Id("1").
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
提示:更多细节请参考后续章节