在 Go 中整合 Elasticsearch
1. 客戶端函式庫選擇
1.1 主流 Go ES 客戶端
- olivere/elastic:功能最全面,API 設計優雅,支援 ES 7.x/8.x
- elastic/go-elasticsearch:官方客戶端,輕量級,更接近原生 REST API
- go-elasticsearch/elasticsearch:社群維護的官方客戶端分支
1.2 推薦選擇
olivere/elastic 是生產環境首選,原因:
- 型別安全的查詢建構器
- 完善的錯誤處理
- 支援所有 ES 功能(聚合、批次操作、索引管理等)
- 活躍維護,版本更新及時
2. olivere/elastic 快速入門
2.1 安裝依賴
go mod init your-project
go get github.com/olivere/elastic/v7
2.2 基礎連線
package main
import (
"context"
"fmt"
"log"
"github.com/olivere/elastic/v7"
)
func main() {
// 建立客戶端
client, err := elastic.NewClient(
elastic.SetURL("http://localhost:9200"),
elastic.SetSniff(false), // 單節點環境關閉嗅探
elastic.SetHealthcheck(false), // 關閉健康檢查
)
if err != nil {
log.Fatal(err)
}
defer client.Stop()
// 檢查連線
info, code, err := client.Ping("http://localhost:9200").Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("ES 版本: %s, 狀態碼: %d\n", info.Version.Number, code)
}
2.3 連線配置選項
client, err := elastic.NewClient(
elastic.SetURL("http://localhost:9200", "http://localhost:9201"), // 多節點
elastic.SetBasicAuth("username", "password"), // 認證
elastic.SetSniff(true), // 自動發現節點
elastic.SetHealthcheckInterval(10*time.Second), // 健康檢查間隔
elastic.SetMaxRetries(3), // 最大重試次數
elastic.SetRetryStatusCodes(502, 503, 504), // 重試狀態碼
elastic.SetGzip(true), // 啟用壓縮
elastic.SetErrorLog(log.New(os.Stderr, "ES ", log.LstdFlags)), // 錯誤日誌
elastic.SetInfoLog(log.New(os.Stdout, "ES ", log.LstdFlags)), // 資訊日誌
)
3. 索引管理
3.1 建立索引
// 建立索引
createIndex, err := client.CreateIndex("products").
BodyString(`{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"price": {"type": "double"},
"status": {"type": "keyword"},
"created_at": {"type": "date"}
}
}
}`).
Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("索引建立結果: %v\n", createIndex.Acknowledged)
3.2 檢查索引是否存在
exists, err := client.IndexExists("products").Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("索引存在: %v\n", exists)
3.3 刪除索引
deleteIndex, err := client.DeleteIndex("products").Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("索引刪除結果: %v\n", deleteIndex.Acknowledged)
4. 文件操作
4.1 定義文件結構
type Product struct {
ID string `json:"id"`
Title string `json:"title"`
Price float64 `json:"price"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
Tags []string `json:"tags"`
}
4.2 新增文件
// 新增單個文件
product := Product{
ID: "1",
Title: "iPhone 15 Pro",
Price: 7999.0,
Status: "active",
CreatedAt: time.Now(),
Tags: []string{"phone", "apple", "premium"},
}
put1, err := client.Index().
Index("products").
Id("1").
BodyJson(product).
Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("文件索引結果: %s\n", put1.Result)
4.3 取得文件
// 根據 ID 取得文件
get1, err := client.Get().
Index("products").
Id("1").
Do(context.Background())
if err != nil {
log.Fatal(err)
}
if get1.Found {
var product Product
err = json.Unmarshal(get1.Source, &product)
if err != nil {
log.Fatal(err)
}
fmt.Printf("取得文件: %+v\n", product)
}
4.4 更新文件
// 部分更新
update, err := client.Update().
Index("products").
Id("1").
Doc(map[string]interface{}{
"price": 7599.0,
}).
Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("更新結果: %s\n", update.Result)
4.5 刪除文件
delete, err := client.Delete().
Index("products").
Id("1").
Do(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Printf("刪除結果: %s\n", delete.Result)
5. 批次操作
5.1 批次索引
bulkRequest := client.Bulk()
products := []Product{
{ID: "2", Title: "Samsung Galaxy S24", Price: 5999.0, Status: "active", CreatedAt: time.Now()},
{ID: "3", Title: "MacBook Pro M3", Price: 12999.0, Status: "active", CreatedAt: time.Now()},
{ID: "
主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4785