go-elasticsearch: Elastic官方的Go語言客戶端

說明

Elastic官方鼓勵在項目中嘗試用這個包,但請記住以下幾點:

  • 這個項目的工作還在進行中,並非所有計劃的功能和Elasticsearch官方客戶端中的標準(故障重試,節點自動發現等)都實現了。
  • API穩定性無法保證。 儘管公共API的設計非常謹慎,但它們可以根據進一步的探索和用戶反饋以不兼容的方式進行更改。
  • 客戶端的目標是Elasticsearch 7.x版本。後續將添加對6.x和5.x版本API的支持。

安裝

go get安裝這個包:

go get -u github.com/elastic/go-elasticsearch

或者將這個包添加到go.mod文件:

require github.com/elastic/go-elasticsearch v0.0.0

或者克隆這個倉庫:

git clone https://github.com/elastic/go-elasticsearch.git && cd go-elasticsearch

一個完整的示例:

mkdir my-elasticsearch-app && cd my-elasticsearch-app

cat > go.mod <<-END
  module my-elasticsearch-app

  require github.com/elastic/go-elasticsearch v0.0.0
END

cat > main.go <<-END
  package main

  import (
    "log"

    "github.com/elastic/go-elasticsearch"
  )

  func main() {
    es, _ := elasticsearch.NewDefaultClient()
    log.Println(es.Info())
  }
END

go run main.go

用法

elasticsearch包與另外兩個包綁定在一起,esapi用於調用Elasticsearch的API,estransport通過HTTP傳輸數據。

使用elasticsearch.NewDefaultClient()函數創建帶有以下默認設置的客戶端:

es, err := elasticsearch.NewDefaultClient()
if err != nil {
  log.Fatalf("Error creating the client: %s", err)
}

res, err := es.Info()
if err != nil {
  log.Fatalf("Error getting response: %s", err)
}

log.Println(res)

// [200 OK] {
//   "name" : "node-1",
//   "cluster_name" : "go-elasticsearch"
// ...

注意:當導出ELASTICSEARCH_URL環境變量時,它將被用作集羣端點。

使用elasticsearch.NewClient()函數(僅用作演示)配置該客戶端:

cfg := elasticsearch.Config{
  Addresses: []string{
    "http://localhost:9200",
    "http://localhost:9201",
  },
  Transport: &http.Transport{
    MaxIdleConnsPerHost:   10,
    ResponseHeaderTimeout: time.Second,
    DialContext:           (&net.Dialer{Timeout: time.Second}).DialContext,
    TLSClientConfig: &tls.Config{
      MaxVersion:         tls.VersionTLS11,
      InsecureSkipVerify: true,
    },
  },
}

es, err := elasticsearch.NewClient(cfg)
// ...

下面的示例展示了更復雜的用法。它從集羣中獲取Elasticsearch版本,同時索引幾個文檔,並使用響應主體周圍的一個輕量包裝器打印搜索結果。

// $ go run _examples/main.go

package main

import (
  "context"
  "encoding/json"
  "log"
  "strconv"
  "strings"
  "sync"

  "github.com/elastic/go-elasticsearch"
  "github.com/elastic/go-elasticsearch/esapi"
)

func main() {
  log.SetFlags(0)

  var (
    r  map[string]interface{}
    wg sync.WaitGroup
  )

  // Initialize a client with the default settings.
  //
  // An `ELASTICSEARCH_URL` environment variable will be used when exported.
  //
  es, err := elasticsearch.NewDefaultClient()
  if err != nil {
    log.Fatalf("Error creating the client: %s", err)
  }

  // 1. Get cluster info
  //
  res, err := es.Info()
  if err != nil {
    log.Fatalf("Error getting response: %s", err)
  }
  // Deserialize the response into a map.
  if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
    log.Fatalf("Error parsing the response body: %s", err)
  }
  // Print version number.
  log.Printf("~~~~~~~> Elasticsearch %s", r["version"].(map[string]interface{})["number"])

  // 2. Index documents concurrently
  //
  for i, title := range []string{"Test One", "Test Two"} {
    wg.Add(1)

    go func(i int, title string) {
      defer wg.Done()

      // Set up the request object directly.
      req := esapi.IndexRequest{
        Index:      "test",
        DocumentID: strconv.Itoa(i + 1),
        Body:       strings.NewReader(`{"title" : "` + title + `"}`),
        Refresh:    "true",
      }

      // Perform the request with the client.
      res, err := req.Do(context.Background(), es)
      if err != nil {
        log.Fatalf("Error getting response: %s", err)
      }
      defer res.Body.Close()

      if res.IsError() {
        log.Printf("[%s] Error indexing document ID=%d", res.Status(), i+1)
      } else {
        // Deserialize the response into a map.
        var r map[string]interface{}
        if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
          log.Printf("Error parsing the response body: %s", err)
        } else {
          // Print the response status and indexed document version.
          log.Printf("[%s] %s; version=%d", res.Status(), r["result"], int(r["_version"].(float64)))
        }
      }
    }(i, title)
  }
  wg.Wait()

  log.Println(strings.Repeat("-", 37))

  // 3. Search for the indexed documents
  //
  // Use the helper methods of the client.
  res, err = es.Search(
    es.Search.WithContext(context.Background()),
    es.Search.WithIndex("test"),
    es.Search.WithBody(strings.NewReader(`{"query" : { "match" : { "title" : "test" } }}`)),
    es.Search.WithTrackTotalHits(true),
    es.Search.WithPretty(),
  )
  if err != nil {
    log.Fatalf("ERROR: %s", err)
  }
  defer res.Body.Close()

  if res.IsError() {
    var e map[string]interface{}
    if err := json.NewDecoder(res.Body).Decode(&e); err != nil {
      log.Fatalf("error parsing the response body: %s", err)
    } else {
      // Print the response status and error information.
      log.Fatalf("[%s] %s: %s",
        res.Status(),
        e["error"].(map[string]interface{})["type"],
        e["error"].(map[string]interface{})["reason"],
      )
    }
  }

  if err := json.NewDecoder(res.Body).Decode(&r); err != nil {
    log.Fatalf("Error parsing the response body: %s", err)
  }
  // Print the response status, number of results, and request duration.
  log.Printf(
    "[%s] %d hits; took: %dms",
    res.Status(),
    int(r["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64)),
    int(r["took"].(float64)),
  )
  // Print the ID and document source for each hit.
  for _, hit := range r["hits"].(map[string]interface{})["hits"].([]interface{}) {
    log.Printf(" * ID=%s, %s", hit.(map[string]interface{})["_id"], hit.(map[string]interface{})["_source"])
  }

  log.Println(strings.Repeat("=", 37))
}

// ~~~~~~~> Elasticsearch 7.0.0-SNAPSHOT
// [200 OK] updated; version=1
// [200 OK] updated; version=1
// -------------------------------------
// [200 OK] 2 hits; took: 7ms
//  * ID=1, map[title:Test One]
//  * ID=2, map[title:Test Two]
// =====================================

如上述示例所示,esapi包允許通過兩種不同的方式調用Elasticsearch API:通過創建結構(如IndexRequest),並向其傳遞上下文和客戶端來調用其Do()方法,或者通過客戶端上可用的函數(如WithIndex())直接調用其上的Search()函數。更多信息請參閱包文檔。

estransport包處理與Elasticsearch之間的數據傳輸。 目前,這個實現只佔據很小的空間:它只在已配置的集羣端點上進行循環。後續將添加更多功能:重試失敗的請求,忽略某些狀態代碼,自動發現羣集中的節點等等。

Examples

_examples文件夾包含許多全面的示例,可幫助你上手使用客戶端,包括客戶端的配置和自定義,模擬單元測試的傳輸,將客戶端嵌入自定義類型,構建查詢,執行請求和解析迴應。

許可證

遵循Apache License 2.0版本。

參考鏈接:

https://github.com/elastic/go-elasticsearch#go-elasticsearch

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章