golang + ElasticSearch(docker)を触ってみる
はじめに
検索機能をelastic searchを使って実装したいけど、何ができるかわからないし、どうやって実装して良いのかもわからなかったので golangとelastic searchで簡単な実装をしてみようと思います
対象
- golang + elastic searchに興味がある人、初めて触る人
環境
ツール | バージョン |
---|---|
go | 1.16.3 |
docker Engine | 20.10.6 |
docker compose | 1.29.1 |
コンテナを立ち上げる
docker-compose.yml
version: "3.8" services: es: image: docker.elastic.co/elasticsearch/elasticsearch:7.13.1 container_name: elasticsearch environment: - discovery.type=single-node volumes: - ./es/data:/usr/share/elasticsearch/data ports: - 9200:9200 - 9300:9300
docker-compose up
参考: Install Elasticsearch with Docker | Elasticsearch Guide [7.13] | Elastic
Infoを取得してみる
まずはREADMEに書いてあるUsageを参考にコードを書いていきます
func GetInfo() { es, err := elasticsearch.NewDefaultClient() if err != nil { log.Fatal(err) } res, err := es.Info() if err != nil { log.Fatal(err) } defer res.Body.Close() var r map[string]interface{} if err := json.NewDecoder(res.Body).Decode(&r); err != nil { log.Fatal(err) } fmt.Printf("%+v\n", r) }
output
map[cluster_name:docker-cluster cluster_uuid:T38_LnjTS_aBtlDa1lMZIA name:0cdf44e15374 tagline:You Know, for Search version:map[build_date:2021-05-28T17:40:59.346932922Z build_flavor:default build_hash:9a7758028e4ea59bcab41c12004603c5a7dd84a9 build_snapshot:false build_type:docker lucene_version:8.8.2 minimum_index_compatibility_version:6.0.0-beta1 minimum_wire_compatibility_version:6.8.0 number:7.13.1]]
Q, elastic searchのURLなど指定していないけど、なぜアクセスできるのか
A, 何も指定していない時はhttp://localhost:9200
が使用されるから
// 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.
go-elasticsearch/elasticsearch.go at master · elastic/go-elasticsearch · GitHub
データをpostしてみる
func ExampleRequest() { es, err := elasticsearch.NewDefaultClient() if err != nil { log.Fatal(err) } req := esapi.IndexRequest{ Index: "test", DocumentID: strconv.Itoa(1), Body: strings.NewReader(`{"test": "hogehoge"}`), } res, err := req.Do(context.Background(), es) if err != nil { log.Fatal(err) } defer res.Body.Close() if res.IsError() { log.Fatalf("failed to request %+v\n", res) } var r map[string]interface{} if err := json.NewDecoder(res.Body).Decode(&r); err != nil { log.Fatalf("Error parsing the response body: %s", err) } log.Printf("[%s] %s; version=%d", res.Status(), r["result"], int(r["_version"].(float64))) }
output
[201 Created] created; version=1
データを取得してみる
func ExampleSearch() { es, err := elasticsearch.NewDefaultClient() if err != nil { log.Fatal(err) } var buf bytes.Buffer query := map[string]interface{}{ "query": map[string]interface{}{ "match": map[string]interface{}{ "test": "hogehoge", }, }, } if err := json.NewEncoder(&buf).Encode(query); err != nil { log.Fatalf("Error encoding query: %s", err) } 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) } // 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"], ) } var r map[string]interface{} if err := json.NewDecoder(res.Body).Decode(&r); err != nil { log.Fatalf("Error parsing the response body: %s", err) } fmt.Printf("%v\n", r) 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)), ) 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"]) } }
output
map[_shards:map[failed:0 skipped:0 successful:1 total:1] hits:map[hits:[map[_id:1 _index:test _score:0.2876821 _source:map[test:hogehoge] _type:_doc]] max_score:0.2876821 total:map[relation:eq value:1]] timed_out:false took:3] 2021/06/06 20:09:59 [200 OK] 1 hits; took: 3ms 2021/06/06 20:09:59 * ID=1, map[test:hogehoge]
まとめ
ほとんどREADMEのUsageに書いてあるコードを使用しました
環境構築やgo-elasticsearchの使い方がわからないと言う人が多いと思うので、この記事を参考に導入の手助けになればと思います