Skip to content

ElasticSearch

Site officiel : Elasticsearch : Le moteur de recherche et d'analyse distribué officiel | Elastic

Elasticsearch est un moteur de recherche et d'analyse de données distribué, de style RESTful, capable de résoudre divers cas d'utilisation en constante évolution. En tant que cœur de l'Elastic Stack, Elasticsearch stocke vos données de manière centralisée, vous permettant d'effectuer des recherches rapides, d'affiner la pertinence, de réaliser des analyses puissantes et de mettre à l'échelle facilement. Cet article explique comment utiliser Go pour effectuer des opérations de base sur Elasticsearch, comme les opérations CRUD. Si vous ne connaissez pas Elasticsearch, veuillez d'abord l'apprendre par vous-même.

Dépendances

Téléchargez la bibliothèque officielle

bash
$ github.com/elastic/go-elasticsearch/v7

Si vous utilisez ES8, changez de version

bash
$ github.com/elastic/go-elasticsearch/v8

TIP

Cet article utilise ES8 pour la démonstration

Connexion

Utilisez la fonction elasticsearch.NewClient pour établir une nouvelle connexion

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

ES8+ utilise par défaut une connexion HTTPS. Lors de l'établissement d'une connexion HTTPS, vous devez utiliser soit le certificat CA, soit l'empreinte CA, les deux étant générés côté serveur Elasticsearch. Voici un exemple :

go
client, err := elasticsearch.NewClient(elasticsearch.Config{
    Addresses:              []string{"https://192.168.153.132:9200"},
    Username:               "elastic",
    Password:               "TETJ8IY+ifbt8SLc+RRQ",
    CertificateFingerprint: "C0E9867C7D446BFF72FE46E7E9FE3455E970A8ADB0D3DF0E1472D55DB2612CD5",
})

L'API Go fournie par elasticsearch utilise principalement des fonctions optionnelles. Par exemple, vous pouvez tester si le service est disponible via l'API ping :

go
pingResp, err := client.Ping(client.Ping.WithPretty(), client.Ping.WithHuman())
if err != nil {
    panic(err)
}
fmt.Println(pingResp)

Sortie

[200 OK]

Autre exemple, consultez l'état du service via l'API Info :

go
infoResp, err := client.Info(client.Info.WithHuman())
if err != nil {
    panic(err)
}
fmt.Println(infoResp)

Sortie

[200 OK] {
  "name" : "db-debian12",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "OMbDIsNwTFiuyjNF9Xnpbw",
  "version" : {
    "number" : "8.15.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "1a77947f34deddb41af25e6f0ddb8e830159c179",
    "build_date" : "2024-08-05T10:05:34.233336849Z",
    "build_snapshot" : false,
    "lucene_version" : "9.11.1",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

TIP

Pour toute question concernant l'API ES, veuillez consulter la documentation officielle ES Restful API.

Index

Pour opérer sur les index via l'API Go, toutes les API liées aux opérations d'index se trouvent dans la structure esapi.Indices

go
// Indices contains the Indices APIs
type Indices struct {
    AddBlock              IndicesAddBlock
    Analyze               IndicesAnalyze
    ClearCache            IndicesClearCache
    Clone                 IndicesClone
    Close                 IndicesClose
    ...
    ...
  ValidateQuery         IndicesValidateQuery
}

Créer

Créer un index, comme indiqué ci-dessous

json
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "salary": {
        "type": "double"
      }
    }
  }
}

L'opération réelle est similaire à l'envoi d'une requête HTTP

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }
  dsl := bytes.NewBufferString(`{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  },
  "mappings": {
    "properties": {
        "name": {
          "type": "text"
        },
        "age": {
          "type": "long"
        },
        "salary": {
          "type": "double"
        }
      }
  }
}`)

  createIndices := client.Indices.Create
  resp, err := createIndices("user", createIndices.WithBody(dsl))
  if err != nil {
    panic(err)
  }
  fmt.Println(resp)
}

Sortie

json
[200 OK] {"acknowledged":true,"shards_acknowledged":true,"index":"user"}

Obtenir

Obtenir les informations de plusieurs index

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  get := client.Indices.Get
  response, err := get([]string{"user"}, get.WithPretty(), get.WithHuman())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[200 OK] {
  "user" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "name" : {
          "type" : "text"
        },
        "salary" : {
          "type" : "double"
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date_string" : "2024-09-23T04:35:04.528Z",
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "3",
        "provided_name" : "user",
        "creation_date" : "1727066104528",
        "number_of_replicas" : "2",
        "uuid" : "AvhhuqV2ShGkRP9z7XbdDA",
        "version" : {
          "created_string" : "8.14.4-snapshot[8512000]",
          "created" : "8512000"
        }
      }
    }
  }
}

Analyser

Analyser une chaîne de texte pour un index spécifié et retourner le résultat, texte comme suit

json
{
  "analyzer": "standard",
  "text": ["this is a test", "the second text"]
}

Code

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  analyze := client.Indices.Analyze
  dsl := bytes.NewBufferString(`{
  "analyzer" : "standard",
  "text" : ["this is a test", "the second text"]
}`)
  response, err := analyze(analyze.WithIndex("user"), analyze.WithBody(dsl), analyze.WithPretty(), analyze.WithHuman())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[200 OK] {
  "tokens" : [
    {
      "token" : "this",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "is",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "<ALPHANUM>",
      "position" : 1
    },
    {
      "token" : "a",
      "start_offset" : 8,
      "end_offset" : 9,
      "type" : "<ALPHANUM>",
      "position" : 2
    },
    {
      "token" : "test",
      "start_offset" : 10,
      "end_offset" : 14,
      "type" : "<ALPHANUM>",
      "position" : 3
    },
    {
      "token" : "the",
      "start_offset" : 15,
      "end_offset" : 18,
      "type" : "<ALPHANUM>",
      "position" : 104
    },
    {
      "token" : "second",
      "start_offset" : 19,
      "end_offset" : 25,
      "type" : "<ALPHANUM>",
      "position" : 105
    },
    {
      "token" : "text",
      "start_offset" : 26,
      "end_offset" : 30,
      "type" : "<ALPHANUM>",
      "position" : 106
    }
  ]
}

Supprimer

Supprimer plusieurs index spécifiés

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  indicesDelete := client.Indices.Delete
  response, err := indicesDelete([]string{"user"})
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[200 OK] {"acknowledged":true}

Dans ces API, vous pouvez voir que le corps de la requête doit être sérialisé manuellement, l'officiel ne l'a pas mappé en structures Go, et le corps de la réponse doit également être traité manuellement. Ce sont les API les plus couramment utilisées, les autres s'utilisent de manière similaire, sans grande différence.

Document

Créer

Créer un document comme suit

json
{
  "name": "jack",
  "age": 12,
  "salary": 5701.1
}

Code

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  doc := bytes.NewBufferString(`{
    "name": "jack",
    "age": 12,
    "salary": 5701.1
}`)
  create := client.Create
  response, err := create("user", "1", doc, create.WithPretty())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[201 Created] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 3,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

Obtenir

Obtenir un document avec un ID spécifié

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  get := client.Get
  response, err := get("user", "1", get.WithPretty())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[200 OK] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "jack",
    "age" : 12,
    "salary" : 5701.1
  }
}

Mettre à jour

Mettre à jour le contenu d'un document

json
{
  "doc": {
    "name": "jack",
    "age": 35,
    "salary": 5701.1
  }
}

Code

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  doc := bytes.NewBufferString(`{
   "doc":  { "name": "jack",
    "age": 35,
    "salary": 5701.1
}}`)
  update := client.Update
  response, err := update("user", "1", doc, update.WithPretty())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Sortie

json
[200 OK] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 3,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

L'API Update prend également en charge l'utilisation de scripts pour implémenter des opérations comme upsert. Pour en savoir plus, consultez Update API.

Supprimer

Supprimer un document spécifié par son ID

go
func main() {
    client, err := newClient()
    if err != nil {
       panic(err)
    }

    deleteDoc := client.Delete
    response, err := deleteDoc("user", "1", deleteDoc.WithPretty())
    if err != nil {
       panic(err)
    }
    fmt.Println(response)
}

Sortie

json
[200 OK] {
  "_index" : "user",
  "_id" : "1",
  "_version" : 3,
  "result" : "deleted",
  "_shards" : {
    "total" : 3,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

Rechercher

L'API ES la plus couramment utilisée est l'API de recherche. Voici une brève démonstration de son utilisation. D'abord, préparez les données.

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }

  for i := range 10 {
    doc := bytes.NewBufferString(fmt.Sprintf(`{
    "name": "%s",
    "age": %d,
    "salary": %f
}`, randomName(), rand.Intn(18)+18, rand.Float64()))
    create := client.Create
    response, err := create("user", string('0'+i), doc, create.WithPretty())
    if err != nil {
      panic(err)
    }
    fmt.Println(response)
  }
}

func randomName() string {
  var b []byte
  for range 10 {
    b = append(b, byte(rand.Intn(26)+'a'))
  }
  return string(b)
}

L'API de recherche s'utilise exactement comme l'API HTTP habituelle.

Rechercher tous les documents

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }
  dsl := bytes.NewBufferString(`{"query": {"match_all":{}}, "size": 1}`)
  search := client.Search
  response, err := search(search.WithBody(dsl), search.WithPretty())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Rechercher un champ spécifique

go
func main() {
  client, err := newClient()
  if err != nil {
    panic(err)
  }
  dsl := bytes.NewBufferString(`{"query": {"term":{ "age": 22 } }, "size": 1}`)
  search := client.Search
  response, err := search(search.WithBody(dsl), search.WithPretty())
  if err != nil {
    panic(err)
  }
  fmt.Println(response)
}

Résumé

Les opérations de base sont essentiellement celles-ci. L'utilisation est exactement la même que l'API HTTP. Une fois que vous maîtrisez ES, utiliser l'API Go ne posera aucun problème. Pour certaines opérations plus avancées comme cluster, data stream, etc., veuillez les explorer par vous-même.

Golang by www.golangdev.cn edit