当前位置:   article > 正文

golang elasticsearch入门教程

golang es

golang elasticsearch入门教程

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

https://github.com/olivere/elastic

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

版本说明

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

b8011600c3186c51f70ad7ebd1fc3068.png

例如: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会自动安装依赖包。

深入浅出讲解 ElasticSearch的安装与使用【建议收藏】

创建ES客户端

在操作ES之前需要创建一个client,用于操作ES,在创建client的时候需要提供ES连接参数。

  1. package main
  2. import "fmt"
  3. import "github.com/olivere/elastic/v7"
  4. func main() {
  5.         // 创建ES client用于后续操作ES
  6.     client, err := elastic.NewClient(
  7.                 // 设置ES服务地址,支持多个地址
  8.         elastic.SetURL("http://127.0.0.1:9200""http://127.0.0.1:9201"),
  9.                 // 设置基于http base auth验证的账号和密码
  10.         elastic.SetBasicAuth("user""secret"))
  11.     if err != nil {
  12.         // Handle error
  13.         fmt.Printf("连接失败: %v\n", err)
  14.     } else {
  15.         fmt.Println("连接成功")
  16.     }
  17. }

创建索引

  1. package main
  2. import (
  3.     "context"
  4.     "fmt"
  5.         "github.com/olivere/elastic/v7"
  6. )
  7. // 索引mapping定义,这里仿微博消息结构定义
  8. const mapping = `
  9. {
  10.   "mappings": {
  11.     "properties": {
  12.       "user": {
  13.         "type": "keyword"
  14.       },
  15.       "message": {
  16.         "type": "text"
  17.       },
  18.       "image": {
  19.         "type": "keyword"
  20.       },
  21.       "created": {
  22.         "type": "date"
  23.       },
  24.       "tags": {
  25.         "type": "keyword"
  26.       },
  27.       "location": {
  28.         "type": "geo_point"
  29.       },
  30.       "suggest_field": {
  31.         "type": "completion"
  32.       }
  33.     }
  34.   }
  35. }`
  1. //来源:公众号【码农编程进阶笔记】
  2. func main() {
  3.         // 创建client
  4.     client, err := elastic.NewClient(
  5.         elastic.SetURL("http://127.0.0.1:9200""http://127.0.0.1:9201"),
  6.         elastic.SetBasicAuth("user""secret"))
  7.     if err != nil {
  8.         // Handle error
  9.         fmt.Printf("连接失败: %v\n", err)
  10.     } else {
  11.         fmt.Println("连接成功")
  12.     }
  13.     // 执行ES请求需要提供一个上下文对象
  14.     ctx := context.Background()
  15.     
  16.     // 首先检测下weibo索引是否存在
  17.     exists, err := client.IndexExists("weibo").Do(ctx)
  18.     if err != nil {
  19.         // Handle error
  20.         panic(err)
  21.     }
  22.     if !exists {
  23.         // weibo索引不存在,则创建一个
  24.         _, err := client.CreateIndex("weibo").BodyString(mapping).Do(ctx)
  25.         if err != nil {
  26.             // Handle error
  27.             panic(err)
  28.         }
  29.     }
  30. }

提示:后续代码不再提重复提供完整的代码,直接引用client对象,则假定你已经完成包的加载和初始化client对象。

插入一条数据

先定义微博的struct, 跟前面创建的weibo索引结构一一对应。

  1. type Weibo struct {
  2.     User     string                `json:"user"` // 用户
  3.     Message  string                `json:"message"` // 微博内容
  4.     Retweets int                   `json:"retweets"` // 转发数
  5.     Image    string                `json:"image,omitempty"` // 图片
  6.     Created  time.Time             `json:"created,omitempty"` // 创建时间
  7.     Tags     []string              `json:"tags,omitempty"` // 标签
  8.     Location string                `json:"location,omitempty"` //位置
  9.     Suggest  *elastic.SuggestField `json:"suggest_field,omitempty"`
  10. }

上面struct定义的时候,都定义了json结构,因为ES请求使用的是json格式,在发送ES请求的时候,会自动转换成json格式。京东面试题:ElasticSearch深度分页解决方案

使用struct结构插入一条ES文档数据,

  1. // 创建创建一条微博
  2. msg1 := Weibo{User: "olivere", Message: "打酱油的一天", Retweets: 0}
  3. // 使用client创建一个新的文档
  4. put1, err := client.Index().
  5.         Index("weibo"). // 设置索引名称
  6.         Id("1"). // 设置文档id
  7.         BodyJson(msg1). // 指定前面声明的微博内容
  8.         Do(ctx) // 执行请求,需要传入一个上下文对象
  9. if err != nil {
  10.         // Handle error
  11.         panic(err)
  12.     }
  13. fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)

查询数据

  1. // 根据id查询文档
  2. get1, err := client.Get().
  3.         Index("weibo"). // 指定索引名
  4.         Id("1"). // 设置文档id
  5.         Do(ctx) // 执行请求
  6. if err != nil {
  7.     // Handle error
  8.     panic(err)
  9. }
  10. if get1.Found {
  11.     fmt.Printf("文档id=%s 版本号=%d 索引名=%s\n", get1.Id, get1.Version, get1.Index)
  12. }

手动将文档内容转换成go struct对象

  1. msg2 := Weibo{}
  2. // 提取文档内容,原始类型是json数据
  3. data, _ := get1.Source.MarshalJSON()
  4. // 将json转成struct结果
  5. json.Unmarshal(data, &msg2)
  6. // 打印结果
  7. fmt.Println(msg2.Message)

更新数据

  1. //根据文档id更新内容
  2. _, err := client.Update().
  3.         Index("weibo"). // 设置索引名
  4.         Id("1"). // 文档id
  5.         Doc(map[string]interface{}{"retweets"0}). // 更新retweets=0,支持传入键值结构
  6.         Do(ctx) // 执行ES查询
  7. if err != nil {
  8.    // Handle error
  9.    panic(err)
  10. }

删除数据

  1. // 根据id删除一条数据
  2. _, err := client.Delete().
  3.         Index("weibo").
  4.         Id("1").
  5.         Do(ctx)
  6. if err != nil {
  7.     // Handle error
  8.     panic(err)
  9. }

golang elasticsearch连接配置

本节介绍golang elastic client参数详解,主要包括:Elasticsearch基本知识

  1. client, err := elastic.NewClient(
  2.         // elasticsearch 服务地址,多个服务地址使用逗号分隔
  3.         elastic.SetURL("http://10.0.1.1:9200""http://10.0.1.2:9200"),
  4.         // 基于http base auth验证机制的账号和密码
  5.         elastic.SetBasicAuth("user""secret"),
  6.         // 启用gzip压缩
  7.         elastic.SetGzip(true),
  8.         // 设置监控检查时间间隔
  9.         elastic.SetHealthcheckInterval(10*time.Second),
  10.         // 设置请求失败最大重试次数
  11.         elastic.SetMaxRetries(5),
  12.         // 设置错误日志输出
  13.         elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
  14.         // 设置info日志输出
  15.         elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
  16. if err != nil {
  17.     // Handle error
  18.     panic(err)
  19. }
  20. _ = client

golang elasticsearch 文档操作(CRUD)

本节主要介绍go语言对Elasticsearch文档的基础操作:创建、查询、更新、删除。php 使用 ElasticSearch 高级查询、过滤、排序

为了方便演示文档的CRUD操作,我们先定义索引的struct结构

  1. // 定义一个文章索引结构,用来存储文章内容
  2. type Article struct {
  3.     Title   string    // 文章标题
  4.     Content string    // 文章内容
  5.     Author  string    // 作者
  6.     Created time.Time // 发布时间
  7. }

添加文档

  1. package main
  2. import (
  3.     "context"
  4.     "encoding/json"
  5.     "fmt"
  6.     "github.com/olivere/elastic/v7"
  7.     "log"
  8.     "os"
  9.     "time"
  10. )
  11. type Article struct {
  12.     Title   string    // 文章标题
  13.     Content string    // 文章内容
  14.     Author  string    // 作者
  15.     Created time.Time // 发布时间
  16. }
  17. func main() {
  18.         // 创建client连接ES
  19.     client, err := elastic.NewClient(
  20.         // elasticsearch 服务地址,多个服务地址使用逗号分隔
  21.         elastic.SetURL("http://127.0.0.1:9200""http://127.0.0.1:9201"),
  22.         // 基于http base auth验证机制的账号和密码
  23.         elastic.SetBasicAuth("user""secret"),
  24.         // 启用gzip压缩
  25.         elastic.SetGzip(true),
  26.         // 设置监控检查时间间隔
  27.         elastic.SetHealthcheckInterval(10*time.Second),
  28.         // 设置请求失败最大重试次数
  29.         elastic.SetMaxRetries(5),
  30.         // 设置错误日志输出
  31.         elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
  32.         // 设置info日志输出
  33.         elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
  34.     if err != nil {
  35.         // Handle error
  36.         fmt.Printf("连接失败: %v\n", err)
  37.     } else {
  38.         fmt.Println("连接成功")
  39.     }
  40.     // 执行ES请求需要提供一个上下文对象
  41.     ctx := context.Background()
  42.     // 定义一篇博客
  43.     blog := Article{Title:"golang es教程", Content:"go如何操作ES", Author:"tizi", Created:time.Now()}
  44.     // 使用client创建一个新的文档
  45.     put1, err := client.Index().
  46.         Index("blogs"). // 设置索引名称
  47.         Id("1"). // 设置文档id
  48.         BodyJson(blog). // 指定前面声明struct对象
  49.         Do(ctx) // 执行请求,需要传入一个上下文对象
  50.     if err != nil {
  51.         // Handle error
  52.         panic(err)
  53.     }
  54.     fmt.Printf("文档Id %s, 索引名 %s\n", put1.Id, put1.Index)
  55. }

提示:后续的章节不再重复给出完整的代码,仅给出关键代码片段

查询文档

  1. 根据文档ID,查询文档
  2. // 根据id查询文档
  3. get1, err := client.Get().
  4.         Index("blogs"). // 指定索引名
  5.         Id("1"). // 设置文档id
  6.         Do(ctx) // 执行请求
  7. if err != nil {
  8.     // Handle error
  9.     panic(err)
  10. }
  11. if get1.Found {
  12.     fmt.Printf("文档id=%s 版本号=%d 索引名=%s\n", get1.Id, get1.Version, get1.Index)
  13. }
  14. # 手动将文档内容转换成go struct对象
  15. msg2 := Article{}
  16. // 提取文档内容,原始类型是json数据
  17. data, _ := get1.Source.MarshalJSON()
  18. // 将json转成struct结果
  19. json.Unmarshal(data, &msg2)
  20. // 打印结果
  21. fmt.Println(msg2.Title)

批量查询文档

  1. 通过多个Id批量查询文档,对应ES的multi get
  2. // 查询id等于1,2,3的博客内容
  3.     result, err := client.MultiGet().
  4.         Add(elastic.NewMultiGetItem(). // 通过NewMultiGetItem配置查询条件
  5.             Index("blogs"). // 设置索引名
  6.             Id("1")). // 设置文档id
  7.         Add(elastic.NewMultiGetItem().Index("blogs").Id("2")).
  8.         Add(elastic.NewMultiGetItem().Index("blogs").Id("3")).
  9.         Do(ctx) // 执行请求
  10.     
  11.     if err != nil {
  12.         panic(err)
  13.     }
  14.     // 遍历文档
  15.     for _, doc := range result.Docs {
  16.         // 转换成struct对象
  17.         var content Article
  18.         tmp, _ := doc.Source.MarshalJSON()
  19.         err := json.Unmarshal(tmp, &content)
  20.         if err != nil {
  21.             panic(err)
  22.         }
  23.         fmt.Println(content.Title)
  24.     }

更新文档

  1. //根据id更新文档
  2. _, err := client.Update().
  3.         Index("blogs"). // 设置索引名
  4.         Id("1"). // 文档id
  5.         Doc(map[string]interface{}{"Title""新的文章标题"}). // 更新Title="新的文章标题",支持传入键值结构
  6.         Do(ctx) // 执行ES查询
  7. if err != nil {
  8.    // Handle error
  9.    panic(err)
  10. }

根据条件更新文档

  1. //支持批量更新文档内容
  2. _, err = client.UpdateByQuery("blogs").
  3.                 // 设置查询条件,这里设置Author=tizi
  4.         Query(elastic.NewTermQuery("Author""tizi")).
  5.                 // 通过脚本更新内容,将Title字段改为1111111
  6.         Script(elastic.NewScript( "ctx._source['Title']='1111111'")).
  7.                 // 如果文档版本冲突继续执行
  8.         ProceedOnVersionConflict(). 
  9.         Do(ctx)

提示: 复杂查询条件,请参考go es查询用法

删除文档

  1. // 根据id删除一条数据
  2. _, err := client.Delete().
  3.         Index("blogs").
  4.         Id("1").  // 文档id
  5.         Do(ctx)
  6. if err != nil {
  7.     // Handle error
  8.     panic(err)
  9. }

根据条件删除文档

  1. _, _ = client.DeleteByQuery("blogs"). // 设置索引名
  2.         // 设置查询条件为: Author = tizi
  3.         Query(elastic.NewTermQuery("Author""tizi")).
  4.         // 文档冲突也继续删除
  5.         ProceedOnVersionConflict().
  6.         Do(ctx)

提示: 复杂查询条件,请参考go es查询用法:https://www.tizi365.com/archives/858.html

elasticsearch当中怎么实现GEO位置搜索

ElasticSearch近实时搜索的实现

golang elasticsearch 查询教程

elasticsearch的查询语法比较丰富,下面分别介绍golang 的各种查询用法。

如果对ES的查询语法和概念不了解,请阅读:Elasticsearch基本知识

1.精确匹配单个字段

elasticsearch的term查询,下面给出完整的代码

  1. package main
  2. import (
  3.     "context"
  4.     "fmt"
  5.     "github.com/olivere/elastic/v7"
  6.     "log"
  7.     "os"
  8.     "reflect"
  9.     "time"
  10. )
  11. type Article struct {
  12.     Title   string    // 文章标题
  13.     Content string    // 文章内容
  14.     Author  string    // 作者
  15.     Created time.Time // 发布时间
  16. }
  17. func main() {
  18.         // 创建Client, 连接ES
  19.     client, err := elastic.NewClient(
  20.         // elasticsearch 服务地址,多个服务地址使用逗号分隔
  21.         elastic.SetURL("http://127.0.0.1:9200""http://127.0.0.1:9201"),
  22.         // 基于http base auth验证机制的账号和密码
  23.         elastic.SetBasicAuth("user""secret"),
  24.         // 启用gzip压缩
  25.         elastic.SetGzip(true),
  26.         // 设置监控检查时间间隔
  27.         elastic.SetHealthcheckInterval(10*time.Second),
  28.         // 设置请求失败最大重试次数
  29.         elastic.SetMaxRetries(5),
  30.         // 设置错误日志输出
  31.         elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
  32.         // 设置info日志输出
  33.         elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)))
  34.     if err != nil {
  35.         // Handle error
  36.         fmt.Printf("连接失败: %v\n", err)
  37.     } else {
  38.         fmt.Println("连接成功")
  39.     }
  40.     // 执行ES请求需要提供一个上下文对象
  41.     ctx := context.Background()
  42.     // 创建term查询条件,用于精确查询
  43.     termQuery := elastic.NewTermQuery("Author""tizi")
  44.     
  45.     searchResult, err := client.Search().
  46.         Index("blogs").   // 设置索引名
  47.         Query(termQuery).   // 设置查询条件
  48.         Sort("Created"true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
  49.         From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
  50.         Size(10).   // 设置分页参数 - 每页大小
  51.         Pretty(true).       // 查询结果返回可读性较好的JSON格式
  52.         Do(ctx)             // 执行请求
  53.     if err != nil {
  54.         // Handle error
  55.         panic(err)
  56.     }
  57.     fmt.Printf("查询消耗时间 %d ms, 结果总数: %d\n", searchResult.TookInMillis, searchResult.TotalHits())
  58.     if searchResult.TotalHits() > 0 {
  59.         // 查询结果不为空,则遍历结果
  60.         var b1 Article
  61.         // 通过Each方法,将es结果的json结构转换成struct对象
  62.         for _, item := range searchResult.Each(reflect.TypeOf(b1)) {
  63.             // 转换成Article对象
  64.             if t, ok := item.(Article); ok {
  65.                 fmt.Println(t.Title)
  66.             }
  67.         }
  68.     }
  69. }

提示:后续章节,仅给出关键代码片段,其他代码结构参考本节即可

2.通过terms实现SQL的in查询

通过terms查询语法实现,多值查询效果用ElasticSearch实现基于标签的兴趣推荐

例子:

  1. // 创建terms查询条件
  2. termsQuery := elastic.NewTermsQuery("Author""tizi""tizi365")
  3. searchResult, err := client.Search().
  4.         Index("blogs").   // 设置索引名
  5.         Query(termsQuery).   // 设置查询条件
  6.         Sort("Created"true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
  7.         From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
  8.         Size(10).   // 设置分页参数 - 每页大小
  9.         Do(ctx)             // 执行请求

3.匹配单个字段

某个字段使用全文搜索,也就是ES的match语法

例子:

  1. // 创建match查询条件
  2. matchQuery := elastic.NewMatchQuery("Title""golang es教程")
  3. searchResult, err := client.Search().
  4.         Index("blogs").   // 设置索引名
  5.         Query(matchQuery).   // 设置查询条件
  6.         Sort("Created"true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
  7.         From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
  8.         Size(10).   // 设置分页参数 - 每页大小
  9.         Do(ctx)

4.范围查询

实现类似Created > '2020-07-20' and Created < '2020-07-22'的范围查询条件

创建查询表达式例子:

  1. // 例1 等价表达式:Created > "2020-07-20" and Created < "2020-07-29"
  2. rangeQuery := elastic.NewRangeQuery("Created").
  3.         Gt("2020-07-20").
  4.         Lt("2020-07-29")
  5.         
  6. // 例2 等价表达式:id >= 1 and id < 10
  7. rangeQuery := elastic.NewRangeQuery("id").
  8.         Gte(1).
  9.         Lte(10)

5.bool组合查询

bool组合查询,实际上就是组合了前面的查询条件,然后通过类似SQL语句的and和or将查询条件组合起来,不熟悉ES查询语法,请参考ES教程

5.1. must条件

类似SQL的and,代表必须匹配的条件。

  1. // 创建bool查询
  2. boolQuery := elastic.NewBoolQuery().Must()
  3. // 创建term查询
  4. termQuery := elastic.NewTermQuery("Author""tizi")
  5. matchQuery := elastic.NewMatchQuery("Title""golang es教程")
  6. // 设置bool查询的must条件, 组合了两个子查询
  7. // 表示搜索匹配Author=tizi且Title匹配"golang es教程"的文档
  8. boolQuery.Must(termQuery, matchQuery)
  9. searchResult, err := client.Search().
  10.         Index("blogs").   // 设置索引名
  11.         Query(boolQuery).   // 设置查询条件
  12.         Sort("Created"true). // 设置排序字段,根据Created字段升序排序,第二个参数false表示逆序
  13.         From(0). // 设置分页参数 - 起始偏移量,从第0行记录开始
  14.         Size(10).   // 设置分页参数 - 每页大小
  15.         Do(ctx)             // 执行请求
5.2. must_not条件

跟must的作用相反,用法和must类似

  1. // 创建bool查询
  2. boolQuery := elastic.NewBoolQuery().Must()
  3. // 创建term查询
  4. termQuery := elastic.NewTermQuery("Author""tizi")
  5. // 设置bool查询的must not条件
  6. boolQuery.MustNot(termQuery)
5.2. should条件

类似SQL中的 or, 只要匹配其中一个条件即可

  1. // 创建bool查询
  2. boolQuery := elastic.NewBoolQuery().Must()
  3. // 创建term查询
  4. termQuery := elastic.NewTermQuery("Author""tizi")
  5. matchQuery := elastic.NewMatchQuery("Title""golang es教程")
  6. // 设置bool查询的should条件, 组合了两个子查询
  7. // 表示搜索Author=tizi或者Title匹配"golang es教程"的文档
  8. boolQuery.Should(termQuery, matchQuery)
  9. 提示:go的elastic库,组合bool语句的用法,跟ES bool语法类似,可以互相嵌套查询语句。

聚合分析

golang elasticsearch 聚合分析(Aggregation)

elasticsearch聚合分析的概念和语法可以参考:

这里主要介绍golang elasticsearch聚合分析的用法。

我们都知道ES聚合分析主要包括:

  • • 指标聚合

  • • 桶聚合

这两种聚合可以嵌套混合使用,桶聚合通常用于对数据分组,然后分组内的数据可以使用指标聚合汇总数据。

下面看一个综合的聚合分析的例子:

  1. // 创建ES client
  2. client, err := elastic.NewClient()
  3. if err != nil {
  4.     // Handle error
  5.     panic(err)
  6. }
  7. // 创建一个terms聚合,根据user字段分组,同时设置桶排序条件为按计数倒序排序,并且返回前10条桶数据
  8. timeline := elastic.NewTermsAggregation().Field("user").Size(10).OrderByCountDesc()
  9. // 创建Date histogram聚合,根据created时间字段分组,按年分组
  10. histogram := elastic.NewDateHistogramAggregation().Field("created").CalendarInterval("year")
  11. // 设置timeline的嵌套聚合条件,整体意思就是:首先按user字段分组,然后分组数据内,再次根据created时间字段按年分组,进行了两次分组。
  12. timeline = timeline.SubAggregation("history", histogram)
  13. // 执行ES查询
  14. searchResult, err := client.Search().
  15.     Index("twitter").                  // 设置索引名
  16.     Query(elastic.NewMatchAllQuery()). // 设置查询条件
  17.     Aggregation("timeline", timeline). // 设置聚合条件,并为聚合条件设置一个名字
  18.     Pretty(true).                      // 返回可读的json格式
  19.     Do(context.Background())           // 执行
  20. if err != nil {
  21.     // Handle error
  22.     panic(err)
  23. }
  24. // 遍历ES查询结果,因为我们首先使用的是terms聚合条件,
  25. // 所以查询结果先使用Terms函数和聚合条件的名字读取结果。
  26. agg, found := searchResult.Aggregations.Terms("timeline")
  27. if !found {
  28.     // 没有查询到terms聚合结果
  29.     log.Fatalf("we should have a terms aggregation called %q""timeline")
  30. }
  31. // 遍历桶数据
  32. for _, userBucket := range agg.Buckets {
  33.     // 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
  34.     user := userBucket.Key
  35.     // 查询嵌套聚合查询的数据
  36.     // 因为我们使用的是Date histogram聚合,所以需要使用DateHistogram函数和聚合名字获取结果
  37.     histogram, found := userBucket.DateHistogram("history")
  38.     if found {
  39.         // 如果找到Date histogram聚合结果,则遍历桶数据
  40.         for _, year := range histogram.Buckets {
  41.             var key string
  42.             if s := year.KeyAsString; s != nil {
  43.                 // 因为返回的是指针类型,这里做一下取值运算
  44.                 key = *s
  45.             }
  46.             // 打印结果
  47.             fmt.Printf("user %q has %d tweets in %q\n", user, year.DocCount, key)
  48.         }
  49.     }
  50. }

后面的章节再分别介绍指标聚合和桶聚合的详细写法。

golang elasticsearch指标聚合(metrics)

ES指标聚合,就是类似SQL的统计函数,指标聚合可以单独使用,也可以跟桶聚合一起使用,下面介绍golang如何使用ES的指标聚合。

不了解ES指标聚合相关知识,先看一下Elasticsearch 指标聚合教程

1. Value Count

值聚合,主要用于统计文档总数,类似SQL的count函数。

  1. package main
  2. import (
  3.     "context"
  4.     "fmt"
  5.     "github.com/olivere/elastic/v7"
  6.     "time"
  7. )
  8. func main() {
  9.     // 创建ES client
  10.     client, err := elastic.NewClient()
  11.     if err != nil {
  12.         // Handle error
  13.         panic(err)
  14.     }
  15.     // 执行ES请求需要提供一个上下文对象
  16.     ctx := context.Background()
  17.     // 创建Value Count指标聚合
  18.     aggs := elastic.NewValueCountAggregation().
  19.         Field("order_id"// 设置统计字段
  20.     searchResult, err := client.Search().
  21.         Index("kibana_sample_data_flights"). // 设置索引名
  22.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  23.         Aggregation("total", aggs). // 设置聚合条件,并为聚合条件设置一个名字, 支持添加多个聚合条件,命名不一样即可。
  24.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  25.         Do(ctx) // 执行请求
  26.     if err != nil {
  27.         // Handle error
  28.         panic(err)
  29.     }
  30.     // 使用ValueCount函数和前面定义的聚合条件名称,查询结果
  31.     agg, found := searchResult.Aggregations.ValueCount("total")
  32.     if found {
  33.         // 打印结果,注意:这里使用的是取值运算符
  34.         fmt.Println(*agg.Value)
  35.     }
  36. }

提示:go elastic库,所有聚合分析结果都是通过对应的函数获取结果,例如前面的例子,Value Count聚合结果,通过ValueCount函数获取结果,后面继续介绍其他指标聚合的用法。

2.Cardinality

基数聚合,也是用于统计文档的总数,跟Value Count的区别是,基数聚合会去重,不会统计重复的值,类似SQL的count(DISTINCT 字段)用法。

提示:基数聚合是一种近似算法,统计的结果会有一定误差,不过性能很好。

  1. // 创建Cardinality指标聚合
  2. aggs := elastic.NewCardinalityAggregation().
  3.         Field("order_id"// 设置统计字段
  4. searchResult, err := client.Search().
  5.         Index("kibana_sample_data_flights"). // 设置索引名
  6.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  7.         Aggregation("total", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  8.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  9.         Do(ctx) // 执行请求
  10. if err != nil {
  11.     // Handle error
  12.     panic(err)
  13. }
  14. // 使用Cardinality函数和前面定义的聚合条件名称,查询结果
  15. agg, found := searchResult.Aggregations.Cardinality("total")
  16. if found {
  17.     // 打印结果,注意:这里使用的是取值运算符
  18.     fmt.Println(*agg.Value)
  19. }

3.Avg

求平均值

  1. // 创建Avg指标聚合
  2. aggs := elastic.NewAvgAggregation().
  3.         Field("price"// 设置统计字段
  4. searchResult, err := client.Search().
  5.         Index("kibana_sample_data_flights"). // 设置索引名
  6.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  7.         Aggregation("avg_price", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  8.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  9.         Do(ctx) // 执行请求
  10. if err != nil {
  11.     // Handle error
  12.     panic(err)
  13. }
  14. // 使用Avg函数和前面定义的聚合条件名称,查询结果
  15. agg, found := searchResult.Aggregations.Avg("avg_price")
  16. if found {
  17.     // 打印结果,注意:这里使用的是取值运算符
  18.     fmt.Println(*agg.Value)
  19. }
4.Sum

求和计算

  1. // 创建Sum指标聚合
  2. aggs := elastic.NewSumAggregation().
  3.         Field("price"// 设置统计字段
  4. searchResult, err := client.Search().
  5.         Index("kibana_sample_data_flights"). // 设置索引名
  6.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  7.         Aggregation("total_price", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  8.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  9.         Do(ctx) // 执行请求
  10. if err != nil {
  11.     // Handle error
  12.     panic(err)
  13. }
  14. // 使用Sum函数和前面定义的聚合条件名称,查询结果
  15. agg, found := searchResult.Aggregations.Sum("total_price")
  16. if found {
  17.     // 打印结果,注意:这里使用的是取值运算符
  18.     fmt.Println(*agg.Value)
  19. }
5.Max

求最大值

  1. // 创建Sum指标聚合
  2. aggs := elastic.NewMaxAggregation().
  3.         Field("price"// 设置统计字段
  4. searchResult, err := client.Search().
  5.         Index("kibana_sample_data_flights"). // 设置索引名
  6.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  7.         Aggregation("max_price", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  8.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  9.         Do(ctx) // 执行请求
  10. if err != nil {
  11.     // Handle error
  12.     panic(err)
  13. }
  14. // 使用Max函数和前面定义的聚合条件名称,查询结果
  15. agg, found := searchResult.Aggregations.Max("max_price")
  16. if found {
  17.     // 打印结果,注意:这里使用的是取值运算符
  18.     fmt.Println(*agg.Value)
  19. }
6.Min

求最小值

  1. // 创建Min指标聚合
  2. aggs := elastic.NewMinAggregation().
  3.         Field("price"// 设置统计字段
  4.     searchResult, err := client.Search().
  5.         Index("kibana_sample_data_flights"). // 设置索引名
  6.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  7.         Aggregation("min_price", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  8.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  9.         Do(ctx) // 执行请求
  10. if err != nil {
  11.     // Handle error
  12.     panic(err)
  13. }
  14. // 使用Min函数和前面定义的聚合条件名称,查询结果
  15. agg, found := searchResult.Aggregations.Min("min_price")
  16. if found {
  17.     // 打印结果,注意:这里使用的是取值运算符
  18.     fmt.Println(*agg.Value)
  19. }

golang elasticsearch 桶聚合(bucket)

Elasticsearch桶聚合,目的就是数据分组,先将数据按指定的条件分成多个组,然后对每一个组进行统计。

不了解Elasticsearch桶聚合概念,可以先学习下Elasticsearch桶聚合教程:https://www.tizi365.com/archives/646.html

下面分别介绍golang elasticsearch桶聚合的写法

1.Terms聚合
  1. package main
  2. import (
  3.     "context"
  4.     "fmt"
  5.     "github.com/olivere/elastic/v7"
  6.     "log"
  7. )
  8. func main() {
  9.     // 创建ES client
  10.     client, err := elastic.NewClient()
  11.     if err != nil {
  12.         // Handle error
  13.         panic(err)
  14.     }
  15.     // 执行ES请求需要提供一个上下文对象
  16.     ctx := context.Background()
  17.     // 创建Terms桶聚合
  18.     aggs := elastic.NewTermsAggregation().
  19.         Field("shop_id"// 根据shop_id字段值,对数据进行分组
  20.     searchResult, err := client.Search().
  21.         Index("shops"). // 设置索引名
  22.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  23.         Aggregation("shop", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  24.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  25.         Do(ctx) // 执行请求
  26.     if err != nil {
  27.         // Handle error
  28.         panic(err)
  29.     }
  30.     // 使用Terms函数和前面定义的聚合条件名称,查询结果
  31.     agg, found := searchResult.Aggregations.Terms("shop")
  32.     if !found {
  33.         log.Fatal("没有找到聚合数据")
  34.     }
  35.     // 遍历桶数据
  36.     for _, bucket := range agg.Buckets {
  37.         // 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
  38.         bucketValue := bucket.Key
  39.         // 打印结果, 默认桶聚合查询,都是统计文档总数
  40.         fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
  41.     }
  42. }
2.Histogram聚合
  1. // 创建Histogram桶聚合
  2. aggs := elastic.NewHistogramAggregation().
  3.         Field("price"). // 根据price字段值,对数据进行分组
  4.         Interval(50//  分桶的间隔为50,意思就是price字段值按50间隔分组
  5. searchResult, err := client.Search().
  6.         Index("order"). // 设置索引名
  7.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  8.         Aggregation("prices", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  9.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  10.         Do(ctx) // 执行请求
  11. if err != nil {
  12.     // Handle error
  13.     panic(err)
  14. }
  15. // 使用Histogram函数和前面定义的聚合条件名称,查询结果
  16. agg, found := searchResult.Aggregations.Histogram("prices")
  17. if !found {
  18.     log.Fatal("没有找到聚合数据")
  19. }
  20. // 遍历桶数据
  21. for _, bucket := range agg.Buckets {
  22.     // 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
  23.     bucketValue := bucket.Key
  24.     // 打印结果, 默认桶聚合查询,都是统计文档总数
  25.     fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
  26. }
3.Date histogram聚合
  1. // 创DateHistogram桶聚合
  2. aggs := elastic.NewDateHistogramAggregation().
  3.         Field("date"). // 根据date字段值,对数据进行分组
  4.         //  分组间隔:month代表每月、支持minute(每分钟)、hour(每小时)、day(每天)、week(每周)、year(每年)
  5.         CalendarInterval("month").
  6.         // 设置返回结果中桶key的时间格式
  7.         Format("yyyy-MM-dd")
  8. searchResult, err := client.Search().
  9.         Index("order"). // 设置索引名
  10.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  11.         Aggregation("sales_over_time", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  12.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  13.         Do(ctx) // 执行请求
  14. if err != nil {
  15.     // Handle error
  16.     panic(err)
  17. }
  18. // 使用DateHistogram函数和前面定义的聚合条件名称,查询结果
  19. agg, found := searchResult.Aggregations.DateHistogram("sales_over_time")
  20. if !found {
  21.     log.Fatal("没有找到聚合数据")
  22. }
  23. // 遍历桶数据
  24. for _, bucket := range agg.Buckets {
  25.     // 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
  26.     bucketValue := bucket.Key
  27.     // 打印结果, 默认桶聚合查询,都是统计文档总数
  28.     fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
  29. }
4.Range聚合
  1. // 创Range桶聚合
  2. aggs := elastic.NewRangeAggregation().
  3.         Field("price"). // 根据price字段分桶
  4.         AddUnboundedFrom(100). // 范围配置, 0 - 100
  5.         AddRange(100.0200.0). // 范围配置, 100 - 200
  6.         AddUnboundedTo(200.0// 范围配置,> 200的值
  7. searchResult, err := client.Search().
  8.         Index("order"). // 设置索引名
  9.         Query(elastic.NewMatchAllQuery()). // 设置查询条件
  10.         Aggregation("price_ranges", aggs). // 设置聚合条件,并为聚合条件设置一个名字
  11.         Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
  12.         Do(ctx) // 执行请求
  13. if err != nil {
  14.     // Handle error
  15.     panic(err)
  16. }
  17. // 使用Range函数和前面定义的聚合条件名称,查询结果
  18. agg, found := searchResult.Aggregations.Range("price_ranges")
  19. if !found {
  20.     log.Fatal("没有找到聚合数据")
  21. }
  22. // 遍历桶数据
  23. for _, bucket := range agg.Buckets {
  24.     // 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
  25.     bucketValue := bucket.Key
  26.     // 打印结果, 默认桶聚合查询,都是统计文档总数
  27.     fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
  28. }
5.嵌套聚合的用法

任意聚合类型都支持嵌套,桶聚合可以嵌套桶聚合,也可以嵌套指标聚合。

例子:

  1. // 创terms桶聚合
  2. aggs := elastic.NewTermsAggregation().Field("shop_id")
  3. // 创建Sum指标聚合
  4. sumAggs := elastic.NewSumAggregation().Field("price")
  5. // terms聚合嵌套指标聚合
  6. aggs.SubAggregation("total_price", sumAggs)

提示:golang elasticsearch的用法,本质上还是对elasticsearch接口的封装,所以用法跟elasticsearch的语法完全一致。

其他

golang elasticsearch 索引操作API 创建索引

  1. // 创建ES client
  2. client, err := elastic.NewClient()
  3. if err != nil {
  4.     // Handle error
  5.     panic(err)
  6. }
  7. // 执行ES请求需要提供一个上下文对象
  8. ctx := context.Background()
  9. // 索引mapping定义,这里仿微博消息结构定义
  10. const mapping = `
  11. {
  12.   "mappings": {
  13.     "properties": {
  14.       "user": {
  15.         "type": "keyword"
  16.       },
  17.       "message": {
  18.         "type": "text"
  19.       },
  20.       "image": {
  21.         "type": "keyword"
  22.       },
  23.       "created": {
  24.         "type": "date"
  25.       },
  26.       "tags": {
  27.         "type": "keyword"
  28.       },
  29.       "location": {
  30.         "type": "geo_point"
  31.       },
  32.       "suggest_field": {
  33.         "type": "completion"
  34.       }
  35.     }
  36.   }
  37. }`

// 创建索引

  1. _, err = client.CreateIndex("weibo").BodyString(mapping).Do(ctx)
  2. if err != nil {
  3.     // Handle error
  4.     panic(err)
  5. }
删除索引
  1. //删除blog索引
  2. client.DeleteIndex("blog").Do(ctx)
检测索引是否存在
  1. // 检测下weibo索引是否存在
  2. exists, err := client.IndexExists("weibo").Do(ctx)
  3. if err != nil {
  4.     // Handle error
  5.     panic(err)
  6. }

参考:

  • • ES教程: https://www.tizi365.com/archives/590.html

  • • ES聚合分析: https://www.tizi365.com/archives/644.html

f4827e8ba8e6674398efaffe98b2ffae.jpeg

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/633610
推荐阅读
相关标签
  

闽ICP备14008679号