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
$ github.com/elastic/go-elasticsearch/v7Si vous utilisez ES8, changez de version
$ github.com/elastic/go-elasticsearch/v8TIP
Cet article utilise ES8 pour la démonstration
Connexion
Utilisez la fonction elasticsearch.NewClient pour établir une nouvelle connexion
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 :
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 :
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 :
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
// 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
{
"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
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
[200 OK] {"acknowledged":true,"shards_acknowledged":true,"index":"user"}Obtenir
Obtenir les informations de plusieurs index
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
[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
{
"analyzer": "standard",
"text": ["this is a test", "the second text"]
}Code
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
[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
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
[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
{
"name": "jack",
"age": 12,
"salary": 5701.1
}Code
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
[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é
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
[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
{
"doc": {
"name": "jack",
"age": 35,
"salary": 5701.1
}
}Code
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
[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
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
[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.
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
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
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.
