elasticsearch-rails gemを使ってみた
丹内です。
掲題のとおり、railsで簡単にelasticsearchを使えるelasticsearch-railsを使ってみました。
ディレクトリ構成
$ tree -L 1 . ├── docker-compose.yml ├── rails │ ├── Dockerfile │ ├── Gemfile │ ├── Gemfile.lock │ ├── Procfile │ ├── Rakefile │ ├── app │ ├── assets │ ├── bin │ ├── config │ ├── config.ru │ ├── db │ ├── lib │ ├── log │ ├── public │ ├── tmp │ └── vendor └── elasticsearch └── Dockerfile
環境情報
ruby 2.2.4
rails 4.2.5.1
docker 1.10.1
Elasticsearchコンテナ
公式イメージをベースに、kuromojiプラグインをインストールしてビルドします。 Dockerfileは以下です。
FROM elasticsearch:2.2.0 RUN plugin install analysis-kuromoji
Railsコンテナ
まずGemfileに以下を追記し、bundle installします。
gem 'elasticsearch-model' gem 'elasticsearch-rails'
elasticsearch-rails gemはActiveRecordを拡張する形で動きます。
要約すると、Elasticsearch::Model
をincludeしたActiveRecord::Base継承モデルにはimport
メソッドが使えるようになり、それを使うことでElasticsearchにドキュメントを作成することができます。
なので、まずはModelを作成します。migrateも実行します。
class Article < ActiveRecord::Base include Elasticsearch::Model validates :message, presence: true index_name "article-#{Rails.env}" document_type 'sample' end
index_name
やdocument_type
でElasticsearchにドキュメントを作成する際の設定ができます。
あとは、どこかのクラスやJob Queue Workerの処理でArticle.import
を実行されればOKです。
また、Elasticsearchの設定は、config/elasticsearch.yml
に記載します。今回はdocker-composeから環境変数でコンテナをlinkするので、環境変数から受け取れるようにしましょう。
network.host: <%= ENV['ELASTICSEARCH_URL'] | 'localhost' %>
なお、RailsアプリのDockerfileは以下のとおりです。
FROM alpine:3.3 ENV BUILD_PACKAGES="curl-dev ruby-dev build-base" \ DEV_PACKAGES="zlib-dev libxml2-dev libstdc++ libxslt-dev tzdata yaml-dev mysql-client mysql-dev python py-pip python-dev" \ RUBY_PACKAGES="ruby ruby-bigdecimal ruby-irb ruby-json ruby-rake ruby-io-console ruby-json yaml nodejs" RUN apk --no-cache --update --upgrade add $BUILD_PACKAGES $RUBY_PACKAGES $DEV_PACKAGES && \ gem install -N bundler RUN gem install -N nokogiri -- --use-system-libraries && \ gem install -N rails --version "$RAILS_VERSION" && \ echo 'gem: --no-document' >> ~/.gemrc && \ cp ~/.gemrc /etc/gemrc && \ chmod uog+r /etc/gemrc && \ bundle config --global build.nokogiri "--use-system-libraries" && \ bundle config --global build.nokogumbo "--use-system-libraries" && \ find / -type f -iname \*.apk-new -delete && \ rm -rf /var/cache/apk/* && \ rm -rf /usr/lib/lib/ruby/gems/*/cache/* && \ rm -rf ~/.gem RUN mkdir /myapp WORKDIR /myapp ADD Gemfile /myapp/Gemfile ADD Gemfile.lock /myapp/Gemfile.lock RUN bundle install ADD . /myapp EXPOSE 3000 CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]
コンテナ間連携
docker-compose.yml
で以下のように定義します。
rails: build: ./rails volumes: - ./rails:/myapp ports: - "3000:3000" links: - elasticsearch environment: ELASTICSEARCH_URL: elasticsearch elasticsearch: build: ./elasticsearch ports: - "9200:9200"
先ほどconfig/elasticsearch.yml
に設定した環境変数は、このenvironment
で設定されます。
linkされたコンテナはhostsが編集されるため、コンテナのIPが動的に変わっても参照することができます。
動かしてみる
rails consoleで作業します。
$ docker-compose run rails c
まず、インデックスを作成します。
Loading development environment (Rails 4.2.5.1) Frame number: 0/5 [1] pry(main)> Article.__elasticsearch__.create_index! force: true [!!!] Index does not exist (Elasticsearch::Transport::Transport::Errors::NotFound) => {"acknowledged"=>true}
別な端末などで、インデックスの作成を確認します。
$ curl -XGET "$(docker-machine ip):9200/_aliases?pretty" { "article-development" : { "aliases" : { } } }
この時点ではドキュメントはありません。
$ curl -XGET 'localhost:9200/article-development/self/_search' -d '{"query":{"match_all":{}}}' {"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}
rails consleでモデルにデータを保存しimportします。
[2] pry(main)> Article.create(message: 'test') [3] pry(main)> Article.import
Elasticsearchを見ると、ちゃんと保存されていることがわかります。
$ curl -XGET "$(docker-machine ip):9200/article-development/self/_search?pretty" -d '{"query":{"match_all":{}}}' { "took" : 65, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 1.0, "hits" : [ { "_index" : "tweet-development", "_type" : "self", "_id" : "14", "_score" : 1.0, "_source" : { "id" : 1, "message" : "test", "created_at" : "2016-02-23T09:33:30.000Z", "updated_at" : "2016-02-23T09:33:30.000Z" } } ] } }
※簡略化のため、出力の一部を編集しています。
まとめ
Railsから簡単にElasticsearchを使うことができる elasticsearch-rails gemを紹介しました。
ActiveRecord前提なので使いどころを考えることもあるかもしれませんが、このように手軽に使えることは魅力的だと思います。