一架梯子,一头程序猿,仰望星空!

golang elasticsearch入门教程


本教程从go语言角度讲解如何对elasticsearch进行增删改查。

目前golang操作elasticsearch的第三方包中最流行的是:

https://github.com/olivere/elastic

本教程也是基于elastic开发包进行讲解。

版本说明

golang的elastic开发包和elasticsearch版本有一些对应关系,在开发前需要注意下,必须选择正确的版本,下面是golang elastic开发包和elasticsearch版本关系表:

Elasticsearch versionGo Elastic versiongo开发包地址
7.x 7.0 github.com/olivere/elastic/v7
6.x6.0github.com/olivere/elastic
5.x5.0gopkg.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)
}

提示:更多细节请参考后续章节