elasticsearch

package module
v8.0.0-...-3a75724 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2021 License: Apache-2.0 Imports: 12 Imported by: 0

README

go-elasticsearch

The official Go client for Elasticsearch.

GoDoc Go Report Card codecov.io Build Unit Integration API

Compatibility

Language clients are forward compatible; meaning that clients support communicating with greater minor versions of Elasticsearch.

Elastic language clients are also backwards compatible with lesser supported minor Elasticsearch versions.

When using Go modules, include the version in the import path, and specify either an explicit version or a branch:

require github.com/Tritura/go-elasticsearch/v7 7.x
require github.com/Tritura/go-elasticsearch/v7 7.0.0

It's possible to use multiple versions of the client in a single project:

// go.mod
github.com/Tritura/go-elasticsearch/v6 6.x
github.com/Tritura/go-elasticsearch/v7 7.x

// main.go
import (
  elasticsearch6 "github.com/Tritura/go-elasticsearch/v6"
  elasticsearch7 "github.com/Tritura/go-elasticsearch/v7"
)
// ...
es6, _ := elasticsearch6.NewDefaultClient()
es7, _ := elasticsearch7.NewDefaultClient()

The master branch of the client is compatible with the current master branch of Elasticsearch.

Installation

Add the package to your go.mod file:

require github.com/Tritura/go-elasticsearch/v8 master

Or, clone the repository:

git clone --branch master https://github.com/Tritura/go-elasticsearch.git $GOPATH/src/github.com/Tritura/go-elasticsearch

A complete example:

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

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

  require github.com/Tritura/go-elasticsearch/v8 master
END

cat > main.go <<-END
  package main

  import (
    "log"

    "github.com/Tritura/go-elasticsearch/v8"
  )

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

go run main.go

Usage

The elasticsearch package ties together two separate packages for calling the Elasticsearch APIs and transferring data over HTTP: esapi and estransport, respectively.

Use the elasticsearch.NewDefaultClient() function to create the client with the default settings.

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)
}

defer res.Body.Close()
log.Println(res)

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

NOTE: It is critical to both close the response body and to consume it, in order to re-use persistent TCP connections in the default HTTP transport. If you're not interested in the response body, call io.Copy(ioutil.Discard, res.Body).

When you export the ELASTICSEARCH_URL environment variable, it will be used to set the cluster endpoint(s). Separate multiple adresses by a comma.

To set the cluster endpoint(s) programatically, pass a configuration object to the elasticsearch.NewClient() function.

cfg := elasticsearch.Config{
  Addresses: []string{
    "http://localhost:9200",
    "http://localhost:9201",
  },
  // ...
}
es, err := elasticsearch.NewClient(cfg)

To set the username and password, include them in the endpoint URL, or use the corresponding configuration options.

cfg := elasticsearch.Config{
  // ...
  Username: "foo",
  Password: "bar",
}

To set a custom certificate authority used to sign the certificates of cluster nodes, use the CACert configuration option.

cert, _ := ioutil.ReadFile(*cacert)

cfg := elasticsearch.Config{
  // ...
  CACert: cert,
}

To configure other HTTP settings, pass an http.Transport object in the configuration object.

cfg := elasticsearch.Config{
  Transport: &http.Transport{
    MaxIdleConnsPerHost:   10,
    ResponseHeaderTimeout: time.Second,
    TLSClientConfig: &tls.Config{
      MinVersion: tls.VersionTLS11,
      // ...
    },
    // ...
  },
}

See the _examples/configuration.go and _examples/customization.go files for more examples of configuration and customization of the client. See the _examples/security for an example of a security configuration.

The following example demonstrates a more complex usage. It fetches the Elasticsearch version from the cluster, indexes a couple of documents concurrently, and prints the search results, using a lightweight wrapper around the response body.

// $ go run _examples/main.go

package main

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

  "github.com/Tritura/go-elasticsearch/v8"
  "github.com/Tritura/go-elasticsearch/v8/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)
  }
  defer res.Body.Close()
  // Check response status
  if res.IsError() {
    log.Fatalf("Error: %s", res.String())
  }
  // 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 client and server version numbers.
  log.Printf("Client: %s", elasticsearch.Version)
  log.Printf("Server: %s", r["version"].(map[string]interface{})["number"])
  log.Println(strings.Repeat("~", 37))

  // 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()

      // Build the request body.
      var b strings.Builder
      b.WriteString(`{"title" : "`)
      b.WriteString(title)
      b.WriteString(`"}`)

      // Set up the request object.
      req := esapi.IndexRequest{
        Index:      "test",
        DocumentID: strconv.Itoa(i + 1),
        Body:       strings.NewReader(b.String()),
        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
  //
  // Build the request body.
  var buf bytes.Buffer
  query := map[string]interface{}{
    "query": map[string]interface{}{
      "match": map[string]interface{}{
        "title": "test",
      },
    },
  }
  if err := json.NewEncoder(&buf).Encode(query); err != nil {
    log.Fatalf("Error encoding query: %s", err)
  }

  // Perform the search request.
  res, err = es.Search(
    es.Search.WithContext(context.Background()),
    es.Search.WithIndex("test"),
    es.Search.WithBody(&buf),
    es.Search.WithTrackTotalHits(true),
    es.Search.WithPretty(),
  )
  if err != nil {
    log.Fatalf("Error getting response: %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))
}

// Client: 8.0.0-SNAPSHOT
// Server: 8.0.0-SNAPSHOT
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// [201 Created] updated; version=1
// [201 Created] updated; version=1
// -------------------------------------
// [200 OK] 2 hits; took: 5ms
//  * ID=1, map[title:Test One]
//  * ID=2, map[title:Test Two]
// =====================================

As you see in the example above, the esapi package allows to call the Elasticsearch APIs in two distinct ways: either by creating a struct, such as IndexRequest, and calling its Do() method by passing it a context and the client, or by calling the Search() function on the client directly, using the option functions such as WithIndex(). See more information and examples in the package documentation.

The estransport package handles the transfer of data to and from Elasticsearch, including retrying failed requests, keeping a connection pool, discovering cluster nodes and logging.

Read more about the client internals and usage in the following blog posts:

Helpers

The esutil package provides convenience helpers for working with the client. At the moment, it provides the esutil.JSONReader() and the esutil.BulkIndexer helpers.

Examples

The _examples folder contains a number of recipes and comprehensive examples to get you started with the client, including configuration and customization of the client, using a custom certificate authority (CA) for security (TLS), mocking the transport for unit tests, embedding the client in a custom type, building queries, performing requests individually and in bulk, and parsing the responses.

License

(c) 2019 Elasticsearch. Licensed under the Apache License, Version 2.0.

Documentation

Overview

Package elasticsearch provides a Go client for Elasticsearch.

Create the client with the NewDefaultClient function:

elasticsearch.NewDefaultClient()

The ELASTICSEARCH_URL environment variable is used instead of the default URL, when set. Use a comma to separate multiple URLs.

To configure the client, pass a Config object to the NewClient function:

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

elasticsearch.NewClient(cfg)

When using the Elastic Service (https://elastic.co/cloud), you can use CloudID instead of Addresses. When either Addresses or CloudID is set, the ELASTICSEARCH_URL environment variable is ignored.

See the elasticsearch_integration_test.go file and the _examples folder for more information.

Call the Elasticsearch APIs by invoking the corresponding methods on the client:

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

log.Println(res)

See the github.com/Tritura/go-elasticsearch/esapi package for more information about using the API.

See the github.com/Tritura/go-elasticsearch/estransport package for more information about configuring the transport.

Index

Examples

Constants

View Source
const (
	Version = version.Client
)

Version returns the package version as a string.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	*esapi.API // Embeds the API methods
	Transport  estransport.Interface
	// contains filtered or unexported fields
}

Client represents the Elasticsearch client.

func NewClient

func NewClient(cfg Config) (*Client, error)

NewClient creates a new client with configuration from cfg.

It will use http://localhost:9200 as the default address.

It will use the ELASTICSEARCH_URL environment variable, if set, to configure the addresses; use a comma to separate multiple URLs.

If either cfg.Addresses or cfg.CloudID is set, the ELASTICSEARCH_URL environment variable is ignored.

It's an error to set both cfg.Addresses and cfg.CloudID.

Example
cfg := elasticsearch.Config{
	Addresses: []string{
		"http://localhost:9200",
	},
	Username: "foo",
	Password: "bar",
	Transport: &http.Transport{
		MaxIdleConnsPerHost:   10,
		ResponseHeaderTimeout: time.Second,
		DialContext:           (&net.Dialer{Timeout: time.Second}).DialContext,
		TLSClientConfig: &tls.Config{
			MinVersion: tls.VersionTLS11,
		},
	},
}

es, _ := elasticsearch.NewClient(cfg)
log.Print(es.Transport.(*estransport.Client).URLs())
Output:

Example (Logger)
// import "github.com/Tritura/go-elasticsearch/v8/estransport"

// Use one of the bundled loggers:
//
// * estransport.TextLogger
// * estransport.ColorLogger
// * estransport.CurlLogger
// * estransport.JSONLogger

cfg := elasticsearch.Config{
	Logger: &estransport.ColorLogger{Output: os.Stdout},
}

elasticsearch.NewClient(cfg)
Output:

func NewDefaultClient

func NewDefaultClient() (*Client, error)

NewDefaultClient creates a new client with default options.

It will use http://localhost:9200 as the default address.

It will use the ELASTICSEARCH_URL environment variable, if set, to configure the addresses; use a comma to separate multiple URLs.

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

res, err := es.Info()
if err != nil {
	log.Fatalf("Error getting the response: %s\n", err)
}
defer res.Body.Close()

log.Print(es.Transport.(*estransport.Client).URLs())
Output:

func (*Client) DiscoverNodes

func (c *Client) DiscoverNodes() error

DiscoverNodes reloads the client connections by fetching information from the cluster.

func (*Client) Metrics

func (c *Client) Metrics() (estransport.Metrics, error)

Metrics returns the client metrics.

func (*Client) Perform

func (c *Client) Perform(req *http.Request) (*http.Response, error)

Perform delegates to Transport to execute a request and return a response.

type Config

type Config struct {
	Addresses []string // A list of Elasticsearch nodes to use.
	Username  string   // Username for HTTP Basic Authentication.
	Password  string   // Password for HTTP Basic Authentication.

	CloudID      string // Endpoint for the Elastic Service (https://elastic.co/cloud).
	APIKey       string // Base64-encoded token for authorization; if set, overrides username/password and service token.
	ServiceToken string // Service token for authorization; if set, overrides username/password.

	Header http.Header // Global HTTP request header.

	// PEM-encoded certificate authorities.
	// When set, an empty certificate pool will be created, and the certificates will be appended to it.
	// The option is only valid when the transport is not specified, or when it's http.Transport.
	CACert []byte

	RetryOnStatus        []int // List of status codes for retry. Default: 502, 503, 504.
	DisableRetry         bool  // Default: false.
	EnableRetryOnTimeout bool  // Default: false.
	MaxRetries           int   // Default: 3.

	CompressRequestBody bool // Default: false.

	DiscoverNodesOnStart  bool          // Discover nodes when initializing the client. Default: false.
	DiscoverNodesInterval time.Duration // Discover nodes periodically. Default: disabled.

	EnableMetrics     bool // Enable the metrics collection.
	EnableDebugLogger bool // Enable the debug logging.

	DisableMetaHeader bool // Disable the additional "X-Elastic-Client-Meta" HTTP header.

	RetryBackoff func(attempt int) time.Duration // Optional backoff duration. Default: nil.

	Transport http.RoundTripper    // The HTTP transport object.
	Logger    estransport.Logger   // The logger object.
	Selector  estransport.Selector // The selector object.

	// Optional constructor function for a custom ConnectionPool. Default: nil.
	ConnectionPoolFunc func([]*estransport.Connection, estransport.Selector) estransport.ConnectionPool
}

Config represents the client configuration.

Directories

Path Synopsis
Package esapi provides the Go API for Elasticsearch.
Package esapi provides the Go API for Elasticsearch.
Package estransport provides the transport layer for the Elasticsearch client.
Package estransport provides the transport layer for the Elasticsearch client.
Package esutil provides helper utilities to the Go client for Elasticsearch.
Package esutil provides helper utilities to the Go client for Elasticsearch.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL