DEV Community

Kentaro KAZAMA
Kentaro KAZAMA

Posted on

Go と Elasticsearch の連携手法について

注意

この記事は,2018年3月6日に書いたものです.

Introduction

本記事では,全文検索エンジンである Elasticsearch を Go言語 から扱うための手法についてまとめます.Elasticsearch を Go とを連携するための手法は,検索してもあまり多くの情報が出てきません.その上,若干つまづきやすいポイントもありますので,この記事が,Elasticsearch と Go を連携しようと苦慮している人の助けになれば幸いです.

Docker による準備

主題に入る前に,そもそも,Elasticsearch と Go を連携するための手法が必要になってきます.本記事では,Docker と docker-compose を併用した連携手法を提示します.

Go のために,下記のような Dockerfile を用意しましょう.

FROM golang:1.9
ENV APPNAME TestApp
RUN mkdir -p /go/src/$APPNAME
WORKDIR /go/src/$APPNAME
ADD . /go/src/$APPNAME
RUN go get -v

これを,Elasticsearch と連携したい Go サーバのトップディレクトリに設置します.次に,下記のような docker-compose.yml を作成します.

version: '3'
services:
  app:
    build: .
    command: ["./wait-for-it.sh", "elastic:9200", "-t", "30", "--", "go", "run", "main.go"]
    volumes:
      - .:/go/src/TestApp
    ports:
      - "8080:8080"
    depends_on:
      - elasticsearch
  elasticsearch:
    image: elasticsearch
    command: elasticsearch
    ports:
      - "9200:9200"

何てことのない普通の docker-compose.yml ですが,注意する点がいくつかあります.Elasticsearch サーバが起動しきっていない状態で Go サーバが起動してはいけないので, wait-for-it.sh というシェルスクリプトを用いて,Go サーバが起動するまで 30 秒の遅延を置くことにしています. なお,参考にした Medium の記事を文献 [1] に示します.

ちなみに, wait-for-it.sh は,下記のリンクから取得することができます.

https://github.com/vishnubob/wait-for-it/blob/master/wait-for-it.sh

これにて,Elasticsearch と Go を連携するための準備は終わりです.次節に,Elasticsearch と Go を連携するためのパッケージの紹介とその手法について述べます.

Elasticsearch と Go

Elasticsearch を Go から呼出す方法はいくつかあります.例えば,Elastic 社公式のクライアントとして go-elasticsearch がありますが,こちらは WIP です.elastic という著名なパッケージがありますので,通常はこちらを使用しましょう.以下に godoc を示します.

https://godoc.org/github.com/olivere/elastic

さてやるぞ,と思って,前節で構築した環境で, GoDoc の通り動かそうとすると失敗します.おそらく, No Elasticsearch Node Available と表示されるはずです.

このようなエラーが発生する理由ですが,Docker コンテナから返ってくる Elasticsearch サーバの IP アドレスは Private なものであるため,外部からアクセスできないということだそうです [2][3].Sniffing をオフにすれば外部 IP からアクセスできますので,そのようにしましょう.下記の通りにすれば,正しく接続できるはずです.

client, err := elastic.NewClient(elastic.SetURL("http://elasticsearch:9200"))
if err != nil {
  panic(err)
}

あとは,下記の通りにすれば Elasticsearch サーバに向けて REST リクエストなどを送ることができますし,Gin などと連携して HTTP Client を作ることもできます.

package main
import (
   "github.com/olivere/elastic"
   "context"
)
func main() {
   client, err := elastic.NewClient(
      elastic.SetURL("http://elasticsearch:9200"),
      elastic.SetSniff(false),
   )
   if err != nil {
      panic(err)
   }
   defer client.Stop()
   resp, err := client.Get().
      Index("index").
      Type("Type").
      Id("Id").
      Do(context.Background())
   if err != nil {
      panic(err)
   }
}

Conclusion

以上,Elasticsearch と Go を連携する上でつまづきやすいポイントのまとめでした.

References

[1] https://medium.com/@leo_hetsch/local-development-with-go-postgresql-and-elasticsearch-in-docker-61bc8a0d5e66

[2] https://github.com/olivere/elastic/issues/312

[3] https://qiita.com/tanan/items/9593927c5b5ae0e811ab

Top comments (0)