目录
一、引入sdk并封装
1、连接初始化
2、封装可调用函数并使用
说明:本节主要说明基于gin 项目的包管理 go modules。
操作环境:linux 64
golang 版本: 1.13.1
如果有相关需要可联系我本人(联系方式可参照置顶文章 :获取我的联系方式)获取。
一个项目的数据来源有很多,比如mysql,mongdb,redis,ES(elasticsearch)。本节先介绍一下如何使用elasticsearch 里的数据。
在golang 中,关于elasticsearch 的第三方包主要有两个:
在这我使用的是第一个,根据服务器的es版本选择olivere/elastic版本。
查看es 版本:
curl -XGET http://自己的服务域名或ip:9200
结果如下,es的版本就是version 里的 number 的值,当前使用的是 6.3.2,对应olivere/elastic 的v6版。https://gopkg.in/olivere/elastic.v6。
{
"name" : "n1",
"cluster_name" : "xxxxxxxx",
"cluster_uuid" : "UnMb3NxxxxxxxxxNfoHziw",
"version" : {
"number" : "6.3.2",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "053779d",
"build_date" : "2018-07-20T05:20:23.451332Z",
"build_snapshot" : false,
"lucene_version" : "7.3.1",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
在 文件中 引入包
import (
····
"gopkg.in/olivere/elastic.v6"
·····
)
在此我封装了一个连接服务。放在 文件夹 connections 中。目录可参照 初探golang和应用其框架 gin 的 使用教程(二)项目布局篇
elastic.go 配置如下:
/**
* @Author: sunct
* @Description:
* @File: elastic.go
* @Version: 1.0.0
* @Date: 2019-10-21 18:06
*/
package connections
import (
"context"
"fmt"
"globaladmin/conf"
"gopkg.in/olivere/elastic.v6"
"log"
"os"
"strconv"
"time"
)
type EsClientType struct {
EsCon *elastic.Client
}
var Timeout="1s" //超时时间
var EsClient EsClientType //连接类型
var host = conf.GetEnv().EsearchServer //这个是es服务地址,我的是配置到配置文件中了,测试的时候可以写死 比如 http://127.0.0.1:9200
//下面定义的是 聚合时候用的一些参数
type Aggregations struct {
AVG_Metric AVG_Metric `json:"AVG_Metric"`
}
type AVG_Metric struct {
Buckets []Metric `json:"buckets"`
}
type Metric struct {
Avg_time Value `json:"avg_time"`
}
type Value struct {
Value float64 `json:"value"`
}
func init(){
elastic.SetSniff(false) //必须 关闭 Sniffing
//es 配置
var err error
//EsClient.EsCon, err = elastic.NewClient(elastic.SetURL(host))
EsClient.EsCon, err =elastic.NewClient(
elastic.SetURL(host),
elastic.SetSniff(false),
elastic.SetHealthcheckInterval(10*time.Second),
elastic.SetGzip(true),
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)),
)
if err != nil {
panic(err)
}
info, code, err := EsClient.EsCon.Ping(host).Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)
esversion, err := EsClient.EsCon.ElasticsearchVersion(host)
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch version %s\n", esversion)
fmt.Println("conn es succ",EsClient.EsCon)
}
//创建
func(client *EsClientType) Create(Params map[string]string) string {
//使用字符串
var res *elastic.IndexResponse
var err error
res,err = client.EsCon.Index().
Index(Params["index"]).
Type(Params["type"]).
Id(Params["id"]).BodyJson(Params["bodyJson"]).
Do(context.Background())
if err != nil {
panic(err)
}
return res.Result
}
//删除
func (client *EsClientType) Delete(Params map[string]string)string {
var res *elastic.DeleteResponse
var err error
res, err = client.EsCon.Delete().Index(Params["index"]).
Type(Params["type"]).
Id(Params["id"]).
Do(context.Background())
if err != nil {
println(err.Error())
}
fmt.Printf("delete result %s\n", res.Result)
return res.Result
}
//修改
func (client *EsClientType) Update(Params map[string]string)string {
var res *elastic.UpdateResponse
var err error
res, err = client.EsCon.Update().
Index(Params["index"]).
Type(Params["type"]).
Id(Params["id"]).
Doc(Params["doc"]).
Do(context.Background())
if err != nil {
println(err.Error())
}
fmt.Printf("update age %s\n", res.Result)
return res.Result
}
//查找
func (client *EsClientType) Gets(Params map[string]string) *elastic.GetResult {
//通过id查找
var get1 *elastic.GetResult
var err error
if len(Params["id"])< 0 {
fmt.Printf("param error")
return get1
}
get1, err = client.EsCon.Get().Index(Params["index"]).Type(Params["type"]).Id(Params["id"]).Do(context.Background())
if err != nil {
panic(err)
}
return get1
}
//搜索
func (client EsClientType) Query(Params map[string]string) *elastic.SearchResult {
var res *elastic.SearchResult
var err error
//取所有
res, err = client.EsCon.Search(Params["index"]).Type(Params["type"]).Do(context.Background())
if len(Params["queryString"]) > 0 {
//字段相等
q := elastic.NewQueryStringQuery(Params["queryString"])
res, err = client.EsCon.Search(Params["index"]).Type(Params["type"]).Query(q).Do(context.Background())
}
if err != nil {
println(err.Error())
}
//if res.Hits.TotalHits > 0 {
// fmt.Printf("Found a total of %d Employee \n", res.Hits.TotalHits)
//}
return res
}
//简单分页 可用
func (client *EsClientType) List(Params map[string]string) *elastic.SearchResult {
var res *elastic.SearchResult
var err error
size, _ := strconv.Atoi(Params["size"])
page, _ := strconv.Atoi(Params["page"])
q := elastic.NewQueryStringQuery(Params["queryString"])
//排序类型 desc asc es 中只使用 bool 值 true or false
sort_type :=true
if Params["sort_type"]=="desc" {
sort_type =false
}
//fmt.Printf(" sort info %s,%s\n", Params["sort"],Params["sort_type"])
if size < 0 || page < 0 {
fmt.Printf("param error")
return res
}
if len(Params["queryString"]) >0 {
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Query(q).
Size(size).
From((page)*size).
Sort(Params["sort"],sort_type).
Timeout(Timeout).
Do(context.Background())
}else{
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Size(size).
From((page)*size).
Sort(Params["sort"],sort_type).
//SortBy(elastic.NewFieldSort("add_time").UnmappedType("long").Desc(), elastic.NewScoreSort()).
Timeout(Timeout).
Do(context.Background())
}
if err != nil {
println("func list error:"+err.Error())
}
return res
}
//聚合 平均 可用
func (client *EsClientType) Aggregation(Params map[string]string) *elastic.SearchResult {
var res *elastic.SearchResult
var err error
//需要聚合的指标 求平均
avg := elastic.NewAvgAggregation().Field(Params["avg"])
//单位时间和指定字段
aggs := elastic.NewDateHistogramAggregation().
Interval("day").
Field(Params["field"]).
//TimeZone("Asia/Shanghai").
SubAggregation(Params["agg_name"], avg)
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Size(0).
Aggregation(Params["aggregation_name"], aggs).
//Sort(Params["sort"],sort_type).
Timeout(Timeout).
Do(context.Background())
if err != nil {
println("func Aggregation error:"+err.Error())
}
println("func Aggregation here 297")
return res
}
或许猛一看这么大段代码有些晕,没关系,代码片段中已写注释。下面单独介绍一下:
func init(){
elastic.SetSniff(false) //必须 关闭 Sniffing
//es 配置
var err error
//EsClient.EsCon, err = elastic.NewClient(elastic.SetURL(host))
EsClient.EsCon, err =elastic.NewClient(
elastic.SetURL(host),
elastic.SetSniff(false),
elastic.SetHealthcheckInterval(10*time.Second),
elastic.SetGzip(true),
elastic.SetErrorLog(log.New(os.Stderr, "ELASTIC ", log.LstdFlags)),
elastic.SetInfoLog(log.New(os.Stdout, "", log.LstdFlags)),
)
if err != nil {
panic(err)
}
info, code, err := EsClient.EsCon.Ping(host).Do(context.Background())
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch returned with code %d and version %s\n", code, info.Version.Number)
esversion, err := EsClient.EsCon.ElasticsearchVersion(host)
if err != nil {
panic(err)
}
fmt.Printf("Elasticsearch version %s\n", esversion)
fmt.Println("conn es succ",EsClient.EsCon)
}
注意:其中第一行,当 sniffing 模式被启用(默认启用),Elastic 使用 Nodes Info API 查找群集中的所有节点。 找到这些节点后,它会定期更新内部连接列表。现在发现的大多数连接问题,都是因为 Elastic 无法调用节点信息API 或无法访问到 Nodes Info API 提供的 IP:Port
组合地址 。
elastic.SetSniff(false) //必须 关闭 Sniffing
假设不关闭,报错信息
no Elasticsearch node available
把连接成功的实例存入全局变量,供其他函数调用,简易连接es方法如下:
EsClient.EsCon, err = elastic.NewClient(elastic.SetURL(host))
在连接es后,根据sdk包里的函数,来封装我们需要的函数供业务使用。目前只使用了后面两个函数:
List: 可搜索的分页列表函数
Aggregation:聚合平均使用的函数(可扩展其他聚合方法,比如 最大值,最小值)
1⃣️List 函数,其中使用Params 里的key值都是自己定义的,比如约定排序是sort ,排序方式是sort_type,搜索是queryString等。如下:
func (client *EsClientType) List(Params map[string]string) *elastic.SearchResult {
var res *elastic.SearchResult
var err error
size, _ := strconv.Atoi(Params["size"])
page, _ := strconv.Atoi(Params["page"])
q := elastic.NewQueryStringQuery(Params["queryString"])
//排序类型 desc asc es 中只使用 bool 值 true or false
sort_type :=true
if Params["sort_type"]=="desc" {
sort_type =false
}
//fmt.Printf(" sort info %s,%s\n", Params["sort"],Params["sort_type"])
if size < 0 || page < 0 {
fmt.Printf("param error")
return res
}
if len(Params["queryString"]) >0 {
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Query(q).
Size(size).
From((page)*size).
Sort(Params["sort"],sort_type).
Timeout(Timeout).
Do(context.Background())
}else{
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Size(size).
From((page)*size).
Sort(Params["sort"],sort_type).
//SortBy(elastic.NewFieldSort("add_time").UnmappedType("long").Desc(), elastic.NewScoreSort()).
Timeout(Timeout).
Do(context.Background())
}
if err != nil {
println("func list error:"+err.Error())
}
return res
}
调用:
//连接es
res:=connections.EsClient.List(params)
解析返回值:
//数据总数
TotalHits:=res.Hits.TotalHits
把内存地址里的值解析出来,主要使用函数
json.Unmarshal()
下面代码中有一个if 判断 type,主要是区分 t 的结构体。
type Employee1 struct {
Id string `json:"_id"`
IP string `json:"ip"`
Visit_count int `json:"visit_count"`
Add_time string `json:"add_time"`
}
type Employee2 struct {
Id string `json:"_id"`
Query_time float64 `json:"query_time"`
Host_ip string `json:"host_ip"`
Db string `json:"db"`
Timestamp time.Time `json:"@timestamp"`
Sql string `json:"sql"`
}
list :=make([]interface{},0)
if TotalHits > 0 {
fmt.Printf("Found a total of %d hits.\n", TotalHits)
// Iterate through results
for _, hit := range res.Hits.Hits {
// Deserialize hit.Source into a Employee (could also be just a map[string]interface{}).
if types ==1 {
var t Employee1
err := json.Unmarshal(*hit.Source, &t)
if err != nil {
// Deserialization failed
}
t.Id = hit.Id
// Work with Employee
list = append(list, t)
}else if types==2 {
var t Employee2
err := json.Unmarshal(*hit.Source, &t)
if err != nil {
// Deserialization failed
}
t.Id = hit.Id
//t.Timestamp=2019-10-24T23:59:59.000000000+08:00"
// Work with Employee
list = append(list, t)
}
}
} else {
// No hits
fmt.Print("Found no result\n")
}
2⃣️Aggregation函数,根据自己需要聚合的参数来约定,比如 需要聚合的求平均值:
//聚合 平均 可用
func (client *EsClientType) Aggregation(Params map[string]string) *elastic.SearchResult {
var res *elastic.SearchResult
var err error
//需要聚合的指标 求平均
avg := elastic.NewAvgAggregation().Field(Params["avg"])
//单位时间和指定字段
aggs := elastic.NewDateHistogramAggregation().
Interval("day").
Field(Params["field"]).
//TimeZone("Asia/Shanghai").
SubAggregation(Params["agg_name"], avg)
res,err = client.EsCon.Search(Params["index"]).
Type(Params["type"]).
Size(0).
Aggregation(Params["aggregation_name"], aggs).
//Sort(Params["sort"],sort_type).
Timeout(Timeout).
Do(context.Background())
if err != nil {
println("func Aggregation error:"+err.Error())
}
println("func Aggregation here 297")
return res
}
调用:
//连接es
res:=connections.EsClient.Aggregation(params)
我使用的参数对应关系如下:
params["avg"] ="query_time" //需要聚合的字段
params["field"]="@timestamp" //聚合的单位时间字段
params["agg_name"]="avg_time" //聚合后的字段名
params["aggregation_name"]="AVG_Metric" //聚合的名字
type Aggregations struct {
AVG_Metric AVG_Metric `json:"AVG_Metric"`
}
type AVG_Metric struct {
Buckets []Metric `json:"buckets"`
}
type Metric struct {
Avg_time Value `json:"avg_time"`
}
type Value struct {
Value float64 `json:"value"`
}
接下来就是解析聚合后的返回值 :
//数据总数
TotalHits:=res.Hits.TotalHits
var avg_time Value
if TotalHits > 0 {
fmt.Printf("Found a total of %d hits\n", TotalHits)
fmt.Println("开始")
var m *[]Metric
term, _ := res.Aggregations.Terms("AVG_Metric")
for _, bucket := range term.Aggregations {
b, _ := bucket.MarshalJSON()
//fmt.Println(string(b))
aa := json.Unmarshal(b, &m)
fmt.Println(aa)
for _, v := range *m {
avg_time = v.Avg_time
}
}
fmt.Println("结束")
} else {
// No hits
fmt.Print("Found no result\n")
}
本项目的具体操作和具体使用将在后续章节中详细说明。
希望本文对你学习有所帮助,感谢您的阅读。