この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
丹内です。
掲題のとおり、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前提なので使いどころを考えることもあるかもしれませんが、このように手軽に使えることは魅力的だと思います。