Go 工程師體系課 012【學習筆記】

在 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

(0)
Walker的頭像Walker
上一篇 2026年3月10日 00:00
下一篇 2026年3月8日 15:40

相關推薦

  • Go 工程師體系課 004【學習筆記】

    需求分析 後台管理系統 商品管理 商品列表 商品分類 品牌管理 品牌分類 訂單管理 訂單列表 使用者資訊管理 使用者列表 使用者地址 使用者留言 輪播圖管理 電商系統 登入頁面 首頁 商品搜尋 商品分類導覽 輪播圖展示 推薦商品展示 商品詳情頁 商品圖片展示 商品描述 商品規格選擇 加入購物車 購物車 商品列表 數量調整 刪除商品 結帳功能 使用者中心 訂單中心 我的…

    2025年11月25日
    27700
  • TS珠峯 004【學習筆記】

    類型體操 type-1 // 內建 // Partial Required Readonly 修飾類型的 // Pick Omit 處理資料結構 // Exclude Extract 處理集合類型的 // Parameters ReturnType infer // 字串類型,樣板字串`${}` + infer PartialPropsOptional …

    個人 2025年3月27日
    1.5K00
  • 深入理解ES6 005【學習筆記】

    解構:使用資料存取更便捷 如果使用 var、let 或 const 解構宣告變數,則必須要提供初始化程式(也就是等號右側的值)如下會導致錯誤 // 語法錯誤 var {tyep,name} // 語法錯誤 let {type,name} // 語法錯誤 const {type,name} 使用解構給已經宣告的變數賦值,如下 let node = { type:&qu…

    個人 2025年3月8日
    1.3K00
  • Go工程師體系課 008【學習筆記】

    訂單及購物車 先從庫存服務中將 srv 的服務程式碼框架複製過來,搜尋取代對應的名稱(order_srv) 加密技術基礎 對稱式加密(Symmetric Encryption) 原理: 使用同一個金鑰進行加密和解密 就像一把鑰匙,既能鎖門也能開門 加密速度快,適合大量資料傳輸 使用情境: 本機檔案加密 資料庫內容加密 大量資料傳輸時的內容加密 內部系統間的快速通…

    個人 2025年11月25日
    26900
  • Go工程師體系課 006【學習筆記】

    專案結構說明:user-web 模組 user-web 是 joyshop_api 專案中的使用者服務 Web 層模組,負責處理使用者相關的 HTTP 請求、參數驗證、業務路由以及呼叫後端介面等功能。以下是目錄結構說明: user-web/ ├── api/ # 控制器層,定義業務介面處理邏輯 ├── config/ # 配置模組,包含系統配置結構體及讀取邏輯 …

    個人 2025年11月25日
    28900