为了便于以后使用ES方便,自己整理了ES使用的demo,如下:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"reflect"
"time"
"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"
}
}
}
}`
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"`
}
func main() {
//BasicOperator()
//DocumentOperator()
//SearchOperator()
MetricsAggregation()
//BucketAggregation()
//AggregationAnalize()
}
//ES基本操作,包括index创建,文档添加,文档查找,文档删除,文档修改
func BasicOperator() {
//创建client参数详解
/*
client, err := elastic.NewClient(
// elasticsearch 服务地址,多个服务地址使用逗号分隔
elastic.SetURL("http://10.0.1.1:9200", "http://10.0.1.2:9200"),
// 基于http base auth验证机制的账号和密码
elastic.SetBasicAuth("user", "secret"),
// 启用gzip压缩
elastic.SetGzip(true),
// 设置监控检查时间间隔
elastic.SetHealthcheckInterval(10*time.Second),
// 设置请求失败最大重试次数
elastic.SetMaxRetries(5),
// 设置错误日志输出
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
// 设置info日志输出
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
if err != nil {
// Handle error
panic(err)
}
_ = client
*/
// 创建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)
}
}
// 创建创建一条微博
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)
//更新数据
updateser, 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)
}
fmt.Println(updateser.Id)
// 根据id删除一条数据
delser, err := client.Delete().
Index("weibo").
Id("1").
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Println(delser.Id)
}
// 定义一个文章索引结构,用来存储文章内容
type Article struct {
Title string // 文章标题
Content string // 文章内容
Author string // 作者
Created time.Time // 发布时间
}
//ES文档操作
func DocumentOperator() {
//1.*****增加文档*****
// 创建client连接ES
client, err := elastic.NewClient(
// elasticsearch 服务地址,多个服务地址使用逗号分隔
elastic.SetURL("http://127.0.0.1:9200", "http://127.0.0.1:9201"),
// 基于http base auth验证机制的账号和密码
elastic.SetBasicAuth("user", "secret"),
// 启用gzip压缩
elastic.SetGzip(true),
// 设置监控检查时间间隔
elastic.SetHealthcheckInterval(10*time.Second),
// 设置请求失败最大重试次数
elastic.SetMaxRetries(5),
// 设置错误日志输出
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
// 设置info日志输出
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
if err != nil {
// Handle error
fmt.Printf("连接失败: %v\n", err)
} else {
fmt.Println("连接成功")
}
// 执行ES请求需要提供一个上下文对象
ctx := context.Background()
// 定义一篇博客
blog := Article{Title: "golang es教程", Content: "go如何操作ES", Author: "tizi", Created: time.Now()}
// 使用client创建一个新的文档
put1, err := client.Index().
Index("blogs"). // 设置索引名称
Id("1"). // 设置文档id
BodyJson(blog). // 指定前面声明struct对象
Do(ctx) // 执行请求,需要传入一个上下文对象
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)
//2.*****查询文档*****
// 根据id查询文档
get1, err := client.Get().
Index("blogs"). // 指定索引名
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 := Article{}
// 提取文档内容,原始类型是json数据
data, _ := get1.Source.MarshalJSON()
// 将json转成struct结果
json.Unmarshal(data, &msg2)
// 打印结果
fmt.Println(msg2.Title)
//3.*****批量查询文档*****
// 查询id等于1,2,3的博客内容
result, err := client.MultiGet().
Add(elastic.NewMultiGetItem(). // 通过NewMultiGetItem配置查询条件
Index("blogs"). // 设置索引名
Id("1")). // 设置文档id
Add(elastic.NewMultiGetItem().Index("blogs").Id("2")).
Add(elastic.NewMultiGetItem().Index("blogs").Id("3")).
Do(ctx) // 执行请求
if err != nil {
panic(err)
}
// 遍历文档
for _, doc := range result.Docs {
// 转换成struct对象
var content Article
tmp, _ := doc.Source.MarshalJSON()
err := json.Unmarshal(tmp, &content)
if err != nil {
panic(err)
}
fmt.Println(content.Title)
}
//4.*****更新文档*****
//4.1***根据id更新文档***
updateser, err := client.Update().
Index("blogs"). // 设置索引名
Id("1"). // 文档id
Doc(map[string]interface{}{"Title": "新的文章标题"}). // 更新Title="新的文章标题",支持传入键值结构
Do(ctx) // 执行ES查询
if err != nil {
// Handle error
panic(err)
}
fmt.Println(updateser.Id)
//4.2***根据条件,批量更新文档***
_, err = client.UpdateByQuery("blogs").
// 设置查询条件,这里设置Author=tizi
Query(elastic.NewTermQuery("Author", "tizi")).
// 通过脚本更新内容,将Title字段改为1111111
Script(elastic.NewScript("ctx._source['Title']='1111111'")).
// 如果文档版本冲突继续执行
ProceedOnVersionConflict().
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
//5.*****删除文档*****
//5.1***根据id删除文档***
delser, err := client.Delete().
Index("blogs").
Id("1"). // 文档id
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Println(delser.Id)
//5.2***根据条件删除文档***
_, _ = client.DeleteByQuery("blogs"). // 设置索引名
// 设置查询条件为: Author = tizi
Query(elastic.NewTermQuery("Author", "tizi")).
// 文档冲突也继续删除
ProceedOnVersionConflict().
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
}
//ES查询操作,文档操作中使用的是get查询
func SearchOperator() {
// 创建Client, 连接ES
client, err := elastic.NewClient(
// elasticsearch 服务地址,多个服务地址使用逗号分隔
elastic.SetURL("http://127.0.0.1:9200", "http://127.0.0.1:9201"),
// 基于http base auth验证机制的账号和密码
elastic.SetBasicAuth("user", "secret"),
// 启用gzip压缩
elastic.SetGzip(true),
// 设置监控检查时间间隔
elastic.SetHealthcheckInterval(10*time.Second),
// 设置请求失败最大重试次数
elastic.SetMaxRetries(5),
// 设置错误日志输出
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
// 设置info日志输出
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
if err != nil {
// Handle error
fmt.Printf("连接失败: %v\n", err)
} else {
fmt.Println("连接成功")
}
// 执行ES请求需要提供一个上下文对象
ctx := context.Background()
/*
//创建数据,以供查找
for i := 10; i < 20; i++ {
title := strconv.Itoa(i) + "golang es教程"
// 定义一篇博客
blog := Article{Title: title, Content: "go如何操作ES", Author: "tizi365", Created: time.Now()}
// 使用client创建一个新的文档
put1, err := client.Index().
Index("blogs"). // 设置索引名称
Id(strconv.Itoa(i)). // 设置文档id
BodyJson(blog). // 指定前面声明struct对象
Do(ctx) // 执行请求,需要传入一个上下文对象
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)
}
*/
//1.*****term查询*****
// 创建term查询条件,用于精确查询
termQuery := elastic.NewTermQuery("Author", "tizi365")
searchResult, err := client.Search().
Index("blogs"). // 设置索引名
Query(termQuery). // 设置查询条件
Sort("Created", true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
Size(10). // 设置分页参数 - 每页大小
Pretty(true). // 查询结果返回可读性较好的JSON格式
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResult.TookInMillis, searchResult.TotalHits())
if searchResult.TotalHits() > 0 {
// 查询结果不为空,则遍历结果
var b1 Article
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range searchResult.Each(reflect.TypeOf(b1)) {
// 转换成Article对象
if t, ok := item.(Article); ok {
fmt.Println(t.Title)
}
}
}
//2.*****通过terms实现SQL的in查询*****
// 创建terms查询条件
termsQuery := elastic.NewTermsQuery("Author", "tizi365", "tizi")
searchResults, err := client.Search().
Index("blogs"). // 设置索引名
Query(termsQuery). // 设置查询条件
Sort("Created", true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
Size(10). // 设置分页参数 - 每页大小
Pretty(true). // 查询结果返回可读性较好的JSON格式
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResults.TookInMillis, searchResults.TotalHits())
if searchResults.TotalHits() > 0 {
// 查询结果不为空,则遍历结果
var b1 Article
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range searchResults.Each(reflect.TypeOf(b1)) {
// 转换成Article对象
if t, ok := item.(Article); ok {
fmt.Println(t.Title)
}
}
}
//3.*****匹配单个字段*****
// 创建match查询条件
matchQuery := elastic.NewMatchQuery("Title", "golang es教程")
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(matchQuery). // 设置查询条件
Sort("Created", true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
Size(10). // 设置分页参数 - 每页大小
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResult.TookInMillis, searchResult.TotalHits())
if searchResult.TotalHits() > 0 {
// 查询结果不为空,则遍历结果
var b1 Article
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range searchResult.Each(reflect.TypeOf(b1)) {
// 转换成Article对象
if t, ok := item.(Article); ok {
fmt.Println(t.Title)
}
}
}
//*****范围查询*****
// 例1 等价表达式: Created > "2020-07-20" and Created < "2020-07-29"
/*
rangeQuery := elastic.NewRangeQuery("Created").
Gt("2020-07-20").
Lt("2020-07-29")
*/
// 例2 等价表达式: id >= 1 and id < 10
rangeQuery := elastic.NewRangeQuery("id").
Gte(8).
Lte(9)
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(rangeQuery). // 设置查询条件
Sort("Created", true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
Size(10). // 设置分页参数 - 每页大小
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResult.TookInMillis, searchResult.TotalHits())
if searchResult.TotalHits() > 0 {
// 查询结果不为空,则遍历结果
var b1 Article
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range searchResult.Each(reflect.TypeOf(b1)) {
// 转换成Article对象
if t, ok := item.(Article); ok {
fmt.Println(t.Title)
}
}
}
//*****5.bool组合查询*****
//bool组合查询,实际上就是组合了前面的查询条件,然后通过类似SQL语句的and和or将查询条件组合起来
//***5.1MUST查询***
//类似SQL的and,代表必须匹配的条件
// 创建bool查询
boolQuery := elastic.NewBoolQuery().Must()
// 创建term查询
termQuery = elastic.NewTermQuery("Author", "tizi")
matchQuery = elastic.NewMatchQuery("Title", "golang es教程")
// 设置bool查询的must条件, 组合了两个子查询
// 表示搜索匹配Author=tizi且Title匹配"golang es教程"的文档
boolQuery.Must(termQuery, matchQuery)
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(boolQuery). // 设置查询条件
Sort("Created", true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
Size(10). // 设置分页参数 - 每页大小
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResult.TookInMillis, searchResult.TotalHits())
if searchResult.TotalHits() > 0 {
// 查询结果不为空,则遍历结果
var b1 Article
// 通过Each方法,将es结果的json结构转换成struct对象
for _, item := range searchResult.Each(reflect.TypeOf(b1)) {
// 转换成Article对象
if t, ok := item.(Article); ok {
fmt.Println(t.Title)
}
}
}
//***5.2must_not查询***
//跟must的作用相反,用法和must类似
// 创建bool查询
boolQuery = elastic.NewBoolQuery().Must()
// 创建term查询
termQuery = elastic.NewTermQuery("Author", "tizi")
// 设置bool查询的must not条件
boolQuery.MustNot(termQuery)
//***5.3should条件***
//类似SQL中的 or, 只要匹配其中一个条件即可
// 创建bool查询
boolQuery = elastic.NewBoolQuery().Must()
// 创建term查询
termQuery = elastic.NewTermQuery("Author", "tizi")
matchQuery = elastic.NewMatchQuery("Title", "golang es教程")
// 设置bool查询的should条件, 组合了两个子查询
// 表示搜索Author=tizi或者Title匹配"golang es教程"的文档
boolQuery.Should(termQuery, matchQuery)
}
//聚合分析:综合例子
func AggregationAnalize() {
// 创建ES client
client, err := elastic.NewClient()
if err != nil {
// Handle error
panic(err)
}
// 创建一个terms聚合,根据user字段分组,同时设置桶排序条件为按计数倒序排序,并且返回前10条桶数据
timeline := elastic.NewTermsAggregation().Field("type").Size(10).OrderByCountDesc()
// 创建Date histogram聚合,根据created时间字段分组,按年分组
histogram := elastic.NewDateHistogramAggregation().Field("created").CalendarInterval("year")
// 设置timeline的嵌套聚合条件,整体意思就是:首先按user字段分组,然后分组数据内,再次根据created时间字段按年分组,进行了两次分组。
timeline = timeline.SubAggregation("history", histogram)
// 执行ES查询
searchResult, err := client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("timeline", timeline). // 设置聚合条件,并为聚合条件设置一个名字
Pretty(true). // 返回可读的json格式
Do(context.Background()) // 执行
if err != nil {
// Handle error
panic(err)
}
// 遍历ES查询结果,因为我们首先使用的是terms聚合条件,
// 所以查询结果先使用Terms函数和聚合条件的名字读取结果。
agg, found := searchResult.Aggregations.Terms("timeline")
if !found {
// 没有查询到terms聚合结果
log.Fatalf("we should have a terms aggregation called %q", "timeline")
}
// 遍历桶数据
for _, userBucket := range agg.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
user := userBucket.Key
// 查询嵌套聚合查询的数据
// 因为我们使用的是Date histogram聚合,所以需要使用DateHistogram函数和聚合名字获取结果
histogram, found := userBucket.DateHistogram("history")
if found {
// 如果找到Date histogram聚合结果,则遍历桶数据
for _, year := range histogram.Buckets {
var key string
if s := year.KeyAsString; s != nil {
// 因为返回的是指针类型,这里做一下取值运算
key = *s
}
// 打印结果
fmt.Printf("user %q has %d tweets in %q\n", user, year.DocCount, key)
}
}
}
}
//聚合分析:指标聚合metrics
//对指标进行统计计算
func MetricsAggregation() {
// 创建ES client
client, err := elastic.NewClient()
if err != nil {
// Handle error
panic(err)
}
// 执行ES请求需要提供一个上下文对象
ctx := context.Background()
// 创建Value Count指标聚合
//值聚合,主要用于统计文档总数,类似SQL的count函数。
aggs := elastic.NewValueCountAggregation().
Field("Created") // 设置统计字段
searchResult, err := client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("total", aggs). // 设置聚合条件,并为聚合条件设置一个名字, 支持添加多个聚合条件,命名不一样即可。
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用ValueCount函数和前面定义的聚合条件名称,查询结果
agg, found := searchResult.Aggregations.ValueCount("total")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
fmt.Println(reflect.TypeOf(*agg.Value))
}
//Cardinality基数聚合
//基数聚合,也是用于统计文档的总数,跟Value Count的区别是,基数聚合会去重,不会统计重复的值,类似SQL的count(DISTINCT 字段)用法
// 创建Cardinality指标聚合
aggss := elastic.NewCardinalityAggregation().
Field("Created") // 设置统计字段
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("total", aggss). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Cardinality函数和前面定义的聚合条件名称,查询结果
agg, found = searchResult.Aggregations.Cardinality("total")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
fmt.Println(reflect.TypeOf(*agg.Value))
}
//Avg聚合:求平均值
// 创建Avg指标聚合
aggs_avg := elastic.NewAvgAggregation().
Field("Created") // 设置统计字段
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("avg_create", aggs_avg). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Avg函数和前面定义的聚合条件名称,查询结果
agg, found = searchResult.Aggregations.Avg("avg_create")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
fmt.Println(reflect.TypeOf(*agg.Value))
}
//Sum聚合:求和计算
// 创建Sum指标聚合
aggs_sum := elastic.NewSumAggregation().
Field("Created") // 设置统计字段
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("total_created", aggs_sum). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Sum函数和前面定义的聚合条件名称,查询结果
agg, found = searchResult.Aggregations.Sum("total_created")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
fmt.Println(reflect.TypeOf(*agg.Value))
}
//Max聚合:求最大值计算
// 创建Sum指标聚合
aggs_max := elastic.NewMaxAggregation().
Field("Created") // 设置统计字段
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("max_created", aggs_max). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Max函数和前面定义的聚合条件名称,查询结果
agg, found = searchResult.Aggregations.Max("max_created")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
fmt.Println(reflect.TypeOf(*agg.Value))
}
//Min聚合:求最小值计算
// 创建Sum指标聚合
aggs_min := elastic.NewMinAggregation().
Field("Created") // 设置统计字段
searchResult, err = client.Search().
Index("blogs"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("min_created", aggs_min). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Max函数和前面定义的聚合条件名称,查询结果
agg, found = searchResult.Aggregations.Max("min_created")
if found {
// 打印结果,注意:这里使用的是取值运算符
fmt.Println(*agg.Value)
}
}
//聚合分析:桶聚合bucket
//Elasticsearch桶聚合,目的就是数据分组,先将数据按指定的条件分成多个组,然后对每一个组进行统计。
func BucketAggregation() {
//CreateBucketAggregationData()
// 创建ES client
client, err := elastic.NewClient()
if err != nil {
// Handle error
panic(err)
}
// 执行ES请求需要提供一个上下文对象
ctx := context.Background()
// 1.*****创建Terms桶聚合*****
aggs := elastic.NewTermsAggregation().
Field("type") // 根据shop_id字段值,对数据进行分组
searchResult, err := client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("shop", aggs). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Terms函数和前面定义的聚合条件名称,查询结果
agg, found := searchResult.Aggregations.Terms("shop")
if !found {
log.Fatal("没有找到聚合数据")
}
// 遍历桶数据
for _, bucket := range agg.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
bucketValue := bucket.Key
// 打印结果, 默认桶聚合查询,都是统计文档总数
fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
}
//2.*****Histogram聚合*****
// 创建Histogram桶聚合
aggs_his := elastic.NewHistogramAggregation().
Field("price"). // 根据price字段值,对数据进行分组
Interval(100) // 分桶的间隔为50,意思就是price字段值按50间隔分组
searchResult, err = client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("prices", aggs_his). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Histogram函数和前面定义的聚合条件名称,查询结果
agg_his, found := searchResult.Aggregations.Histogram("prices")
if !found {
log.Fatal("没有找到聚合数据")
}
// 遍历桶数据
for _, bucket := range agg_his.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
bucketValue := bucket.Key
// 打印结果, 默认桶聚合查询,都是统计文档总数
fmt.Printf("bucket = %v 文档总数 = %d\n", bucketValue, bucket.DocCount)
}
//3.*****Date histogram聚合*****
// 创DateHistogram桶聚合
aggs_datahis := elastic.NewDateHistogramAggregation().
Field("created"). // 根据date字段值,对数据进行分组
// 分组间隔:month代表每月、支持minute(每分钟)、hour(每小时)、day(每天)、week(每周)、year(每年)
CalendarInterval("month").
// 设置返回结果中桶key的时间格式
Format("yyyy-MM-dd")
searchResult, err = client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("sales_over_time", aggs_datahis). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用DateHistogram函数和前面定义的聚合条件名称,查询结果
agg_datahis, found := searchResult.Aggregations.DateHistogram("sales_over_time")
if !found {
log.Fatal("没有找到聚合数据")
}
// 遍历桶数据
for _, bucket := range agg_datahis.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
bucketValue := bucket.Key
// 打印结果, 默认桶聚合查询,都是统计文档总数
fmt.Printf("bucket = %v 文档总数 = %d\n", bucketValue, bucket.DocCount)
}
//4.*****Range聚合*****
// 创Range桶聚合
aggs_ran := elastic.NewRangeAggregation().
Field("price"). // 根据price字段分桶
AddUnboundedFrom(100). // 范围配置, 0 - 100
AddRange(100.0, 200.0). // 范围配置, 100 - 200
AddUnboundedTo(200.0) // 范围配置,> 200的值
searchResult, err = client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("price_ranges", aggs_ran). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Range函数和前面定义的聚合条件名称,查询结果
agg_ran, found := searchResult.Aggregations.Range("price_ranges")
if !found {
log.Fatal("没有找到聚合数据")
}
// 遍历桶数据
for _, bucket := range agg_ran.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
bucketValue := bucket.Key
// 打印结果, 默认桶聚合查询,都是统计文档总数
fmt.Printf("bucket = %v 文档总数 = %d\n", bucketValue, bucket.DocCount)
}
//5.*****嵌套*****
// 创terms桶聚合
aggs_qt := elastic.NewTermsAggregation().Field("type")
// 创建Sum指标聚合
sumAggs_qt := elastic.NewSumAggregation().Field("price")
// terms聚合嵌套指标聚合
timeline := aggs_qt.SubAggregation("total_price", sumAggs_qt)
searchResult, err = client.Search().
Index("shops"). // 设置索引名
Query(elastic.NewMatchAllQuery()). // 设置查询条件
Aggregation("price_ranges", timeline). // 设置聚合条件,并为聚合条件设置一个名字
Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
Do(ctx) // 执行请求
if err != nil {
// Handle error
panic(err)
}
// 使用Range函数和前面定义的聚合条件名称,查询结果
agg_qt, found := searchResult.Aggregations.Range("price_ranges")
if !found {
log.Fatal("没有找到聚合数据")
}
// 遍历桶数据
for _, bucket := range agg_qt.Buckets {
// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
bucketValue := bucket.Key
// 打印结果, 默认桶聚合查询,都是统计文档总数
fmt.Printf("bucket = %v 文档总数 = %d\n", bucketValue, bucket.DocCount)
}
}
type Product struct {
Name string `json:"name"` // 产品名称
Type string `json:"type"` // 产品类型
Price int `json:"price"` // 产品价格
Created time.Time `json:"created"` // 生产时间
}
const mappings = `
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"type": {
"type": "keyword"
},
"created": {
"type": "date"
},
"price": {
"type": "integer"
}
}
}
}`
func CreateBucketAggregationData() {
// 创建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("shops").Do(ctx)
if err != nil {
// Handle error
panic(err)
}
if !exists {
// weibo索引不存在,则创建一个
_, err := client.CreateIndex("shops").BodyString(mappings).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
}
// work
msg1 := Product{Name: "keyboad", Price: 250, Created: time.Now(), Type: "work"}
// 使用client创建一个新的文档
put1, err := client.Index().
Index("shops"). // 设置索引名称
Id("5"). // 设置文档id
BodyJson(msg1). // 指定前面声明的微博内容
Do(ctx) // 执行请求,需要传入一个上下文对象
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)
}
//总结:
//1.使用transname进行桶分组
//2.使用耗时、错误码等进行聚合
//3.根据聚合结果进行数据结果的整合,并将结果输出
备注:可以在梯子网进行学习https://www.tizi365.com/archives/850.html