go-elasticsearch 使用指南
本文是 go-elasticsearch 庫的使用指南。
go-elasticsearch 是 Elasticsearch 官方提供的 Go 客戶端。每個 Elasticsearch 版本會有一個對應的 go-elasticsearch 版本。官方會維護最近的兩個主要版本。
go-elasticsearch 提供了 Low-level 和 Fully-typed 兩套 API。本文以 Fully-typed API 爲例介紹 go-elasticsearch 的常用方法。
關於 Elasticsearch 介紹和如何使用 docker 在本地搭建 Elasticsearch 環境請查看我之前的博客 Elasticsearch 簡明教程。
安裝依賴
執行以下命令安裝 v8 版本的 go 客戶端。
go get github.com/elastic/go-elasticsearch/v8@latest
導入依賴。
import "github.com/elastic/go-elasticsearch/v8"
可以根據實際需求導入不同的客戶端版本,也支持在一個項目中導入不同的客戶端版本。
import (
elasticsearch7 "github.com/elastic/go-elasticsearch/v7"
elasticsearch8 "github.com/elastic/go-elasticsearch/v8"
)
// ...
es7, _ := elasticsearch7.NewDefaultClient()
es8, _ := elasticsearch8.NewDefaultClient()
連接 ES
指定要連接 ES 的相關配置,並創建客戶端連接。
// ES 配置
cfg := elasticsearch.Config{
Addresses: []string{
"http://localhost:9200",
},
}
// 創建客戶端連接
client, err := elasticsearch.NewTypedClient(cfg)
if err != nil {
fmt.Printf("elasticsearch.NewTypedClient failed, err:%v\n", err)
return
}
操作 ES
本文接下來將以電商平臺 "用戶評價" 數據爲例,演示 Go 語言 Elasticsearch 客戶端的相關操作。
創建 index
創建一個名爲 my-review-1
的 index。
// createIndex 創建索引
func createIndex(client *elasticsearch.TypedClient) {
resp, err := client.Indices.
Create("my-review-1").
Do(context.Background())
if err != nil {
fmt.Printf("create index failed, err:%v\n", err)
return
}
fmt.Printf("index:%#v\n", resp.Index)
}
索引 document
定義與 document 數據對應的 Review
和 Tag
結構體,分別表示 "評價" 和 "評價標籤"。
// Review 評價數據
type Review struct {
ID int64 `json:"id"`
UserID int64 `json:"userID"`
Score uint8 `json:"score"`
Content string `json:"content"`
Tags []Tag `json:"tags"`
Status int `json:"status"`
PublishTime time.Time `json:"publishDate"`
}
// Tag 評價標籤
type Tag struct {
Code int `json:"code"`
Title string `json:"title"`
}
創建一條 document 並添加到 my-review-1
的 index 中。
// indexDocument 索引文檔
func indexDocument(client *elasticsearch.TypedClient) {
// 定義 document 結構體對象
d1 := Review{
ID: 1,
UserID: 147982601,
Score: 5,
Content: "這是一個好評!",
Tags: []Tag{
{1000, "好評"},
{1100, "物超所值"},
{9000, "有圖"},
},
Status: 2,
PublishTime: time.Now(),
}
// 添加文檔
resp, err := client.Index("my-review-1").
Id(strconv.FormatInt(d1.ID, 10)).
Document(d1).
Do(context.Background())
if err != nil {
fmt.Printf("indexing document failed, err:%v\n", err)
return
}
fmt.Printf("result:%#v\n", resp.Result)
}
獲取 document
根據 id 獲取 document。
// getDocument 獲取文檔
func getDocument(client *elasticsearch.TypedClient, id string) {
resp, err := client.Get("my-review-1", id).
Do(context.Background())
if err != nil {
fmt.Printf("get document by id failed, err:%v\n", err)
return
}
fmt.Printf("fileds:%s\n", resp.Source_)
}
檢索 document
構建搜索查詢可以使用結構化的查詢條件。
// searchDocument 搜索所有文檔
func searchDocument(client *elasticsearch.TypedClient) {
// 搜索文檔
resp, err := client.Search().
Index("my-review-1").
Request(&search.Request{
Query: &types.Query{
MatchAll: &types.MatchAllQuery{},
},
}).
Do(context.Background())
if err != nil {
fmt.Printf("search document failed, err:%v\n", err)
return
}
fmt.Printf("total: %d\n", resp.Hits.Total.Value)
// 遍歷所有結果
for _, hit := range resp.Hits.Hits {
fmt.Printf("%s\n", hit.Source_)
}
}
下面是在 my-review-1
中搜索 content 包含 "好評" 的文檔。
// searchDocument2 指定條件搜索文檔
func searchDocument2(client *elasticsearch.TypedClient) {
// 搜索content中包含好評的文檔
resp, err := client.Search().
Index("my-review-1").
Request(&search.Request{
Query: &types.Query{
MatchPhrase: map[string]types.MatchPhraseQuery{
"content": {Query: "好評"},
},
},
}).
Do(context.Background())
if err != nil {
fmt.Printf("search document failed, err:%v\n", err)
return
}
fmt.Printf("total: %d\n", resp.Hits.Total.Value)
// 遍歷所有結果
for _, hit := range resp.Hits.Hits {
fmt.Printf("%s\n", hit.Source_)
}
}
聚合
在 my-review-1
上運行一個平均值聚合,得到所有文檔 score 的平均值。
// aggregationDemo 聚合
func aggregationDemo(client *elasticsearch.TypedClient) {
avgScoreAgg, err := client.Search().
Index("my-review-1").
Request(
&search.Request{
Size: some.Int(0),
Aggregations: map[string]types.Aggregations{
"avg_score": { // 將所有文檔的 score 的平均值聚合爲 avg_score
Avg: &types.AverageAggregation{
Field: some.String("score"),
},
},
},
},
).Do(context.Background())
if err != nil {
fmt.Printf("aggregation failed, err:%v\n", err)
return
}
fmt.Printf("avgScore:%#v\n", avgScoreAgg.Aggregations["avg_score"])
}
更新 document
使用新值更新文檔。
// updateDocument 更新文檔
func updateDocument(client *elasticsearch.TypedClient) {
// 修改後的結構體變量
d1 := Review{
ID: 1,
UserID: 147982601,
Score: 5,
Content: "這是一個修改後的好評!", // 有修改
Tags: []Tag{ // 有修改
{1000, "好評"},
{9000, "有圖"},
},
Status: 2,
PublishTime: time.Now(),
}
resp, err := client.Update("my-review-1", "1").
Doc(d1). // 使用結構體變量更新
Do(context.Background())
if err != nil {
fmt.Printf("update document failed, err:%v\n", err)
return
}
fmt.Printf("result:%v\n", resp.Result)
}
更新可以使用結構體變量也可以使用原始 JSON 字符串數據。
// updateDocument2 更新文檔
func updateDocument2(client *elasticsearch.TypedClient) {
// 修改後的JSON字符串
str := `{
"id":1,
"userID":147982601,
"score":5,
"content":"這是一個二次修改後的好評!",
"tags":[
{
"code":1000,
"title":"好評"
},
{
"code":9000,
"title":"有圖"
}
],
"status":2,
"publishDate":"2023-12-10T15:27:18.219385+08:00"
}`
// 直接使用JSON字符串更新
resp, err := client.Update("my-review-1", "1").
Request(&update.Request{
Doc: json.RawMessage(str),
}).
Do(context.Background())
if err != nil {
fmt.Printf("update document failed, err:%v\n", err)
return
}
fmt.Printf("result:%v\n", resp.Result)
}
刪除 document
根據文檔 id 刪除文檔。
// deleteDocument 刪除 document
func deleteDocument(client *elasticsearch.TypedClient) {
resp, err := client.Delete("my-review-1", "1").
Do(context.Background())
if err != nil {
fmt.Printf("delete document failed, err:%v\n", err)
return
}
fmt.Printf("result:%v\n", resp.Result)
}
刪除 index
刪除指定的 index。
// deleteIndex 刪除 index
func deleteIndex(client *elasticsearch.TypedClient) {
resp, err := client.Indices.
Delete("my-review-1").
Do(context.Background())
if err != nil {
fmt.Printf("delete document failed, err:%v\n", err)
return
}
fmt.Printf("Acknowledged:%v\n", resp.Acknowledged)
}
參考資料
elasticsearch go-api
elasticsearch go-api examples
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Em-xPi2ZqBALiFX9ebb2fw