はじめに
Chewyは、RailsのmodelをElasticsearchで扱うためのGemの1つです。
Chewyの日本語記事が大変少ないため、今回記事を書いてみようと思いました。
この記事では、Chewyを用いてとりあえず簡単な検索ができるまでの流れをまとめてみました。
とりあえず動かすことを目的としているので細かな解説は行なっていませんが、
今後少しずつまとめていけたらなと思います。
目標
「タイトル、著者名、出版社名から書籍を検索する」というシンプルな検索をChewyで実装する。
環境
ruby 2.5.3
rails 6.0.0
chewy 0.8.3
Elasticsearch 6.5.4
環境構築
1. Dockerfile,docker-compose.ymlなどを作成する。
chewy_sample
┣ docker
┃ ┣ es
┃ ┃ ┗ Dockerfile
┃ ┗ mysql
┃ ┃ ┣ Dockerfile
┃ ┃ ┗ my.cnf
┣ Dockerfile
┗ docker-compose.yml
FROM ruby:2.5.3-stretch
ENV BUNDLE_GEMFILE=/app/Gemfile \
BUNDLE_JOBS=2 \
RAILS_ENV=development \
LANG=C.UTF-8
RUN apt-get update -qq
RUN apt-get install -y build-essential
RUN apt-get install -y libpq-dev
RUN apt-get install -y nodejs
# ワーキングディレクトリの設定
RUN mkdir /app
WORKDIR /app
version: "3"
services:
es:
build: ./docker/es
container_name: es
environment:
- cluster.name=rails-sample-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- chewy_sample_data:/usr/share/elasticsearch/data
ports:
- 9200:9200
kibana:
image: docker.elastic.co/kibana/kibana:6.5.4
environment:
SERVER_NAME: localhost:5601
ELASTICSEARCH_URL: http://chewy_sample:9200
ports:
- 5601:5601
depends_on:
- es
db:
environment:
- MYSQL_ROOT_PASSWORD=docker
- MYSQL_PASSWORD=docker
- MYSQL_USER=docker
- MYSQL_DATABASE=chewy_sample
build: ./docker/mysql
ports:
- "3306:3306"
rails:
build: .
volumes:
- .:/app
- vendor_bundle:/user/local/bundle
ports:
- "3003:3000"
links:
- db
- es
environment:
- RAILS_DATABASE_USERNAME=root
- RAILS_DATABASE_PASSWORD=docker
- RAILS_DATABASE_NAME=rails_chewy_sample
- RAILS_DATABASE_HOST=db
tty: true
stdin_open: true
volumes:
chewy_sample_data:
driver: local
vendor_bundle:
driver: local
FROM docker.elastic.co/elasticsearch/elasticsearch:6.5.4
# elasticsearchで日本語を扱うために、kuromojiプラグインを導入
RUN bin/elasticsearch-plugin install analysis-kuromoji
FROM mysql:5.7
RUN touch /var/log/mysql/mysqld.log # 指定の場所にログを記録するファイルを作る
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
[client]
port = 3306
socket = /var/run/mysqld/mysqld.sock
default-character-set=utf8
[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
nice = 0
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
lc-messages-dir = /usr/share/mysql
explicit_defaults_for_timestamp
character-set-server=utf8
expire_logs_days = 2
default-time-zone = '+9:00'
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
# bind-address = 127.0.0.1
# log-error = /var/log/mysql/error.log
# Recommended in standard MySQL setup
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
2. railsプロジェクトの作成
$ docker-compose up -d
# Nameの確認
$ docker ps
# docker ps で確認したNameでrailsのコンテナに入る
$ docker exec -it chewy_sample_rails_1 /bin/bash
コンテナ内で下記を実行する
/app# bundle init
Gemfileが生成されるので下記のように編集する
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
# コメントアウトを外す
gem "rails"
Gemfile編集後、コンテナ内で下記コマンドを実行する
# railsのコンテナ内
/app# bundle install
/app# bundle exec rails new .
3. 今回用いるGemを追加する
Gemfileに下記の行を追加する
# mysql2を追加
gem 'mysql2'
# chewyを追加
gem 'chewy', '~> 0.8.3'
# fakerを追加
gem 'faker'
app# bundle install
4. 起動
app# rails s -p 3000 -b '0.0.0.0'
ここまでできたら、http://localhost:3000/にきちんと動作しているかアクセスして確認してみます。
おなじみの画面が表示されたら、OK
Railsの日本語化
必要ないかもしれませんが、Railsの日本語化対応を行います。
下記の記事を参考にRailsの日本語化をさせて頂きました。
[初学者]Railsのi18nによる日本語化対応
また、fakerの日本語化を行います。
ja.ymlをダウンロードして、lib/locales/ja.ymlに配置します。
モデルの作成
書籍とその著者や出版社のデータを格納するテーブルを用意します。
$ rails g model Book title:string author_id:integer publisher_id:integer price:integer
$ rails g model Author name:string
$ rails g model Publisher name:string
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
belongs_to :publisher
end
class Publisher < ApplicationRecord
has_many :books
end
$ rails db:migrate
Chewyの設定
Chewyの設定ファイルの作成
config/chewy.ymlの生成
$ rails g chewy:install
# config/chewy.yml
# separate environment configs
test:
host: "es:9250"
prefix: "test"
development:
host: "es:9200"
Indexの作成
インデックスを作成します。
今回は、本のタイトル、著者名、出版社名で検索
$ mkdir app/chewy
$ touch app/chewy/books_index.rb
class BooksIndex < Chewy::Index
define_type Book do
field :title, type: 'text'
field :author, type: 'text', value: ->(book) { book.author.name }
field :publisher, type: 'text', value: ->(book) { book.publisher.name }
end
end
テストデータの作成
検索できるか試すために、Fakerを用いてテストデータを作成します。
Fakerのロケールの関係で著者名だけが日本人名という変なデータになっちゃいますが、ご愛嬌ということで……
Chewy.strategyを用いることで、データの作成・更新更新に応じて、インデックスも作成・更新されるようになります。
Chewy.strategy(:atomic) do
50.times do |i|
Author.create(
name: Faker::Book.author
)
Publisher.create(
name: Faker::Book.publisher
)
Book.create(
title: Faker::Book.title,
author_id: i+1,
publisher_id: i+1,
price: 450,
)
end
end
$ rails db:seed
もし何らかの不具合で、データとインデックスに相違が生じた場合、下記のコマンドでインデックスのリセットができます。
$ rails chewy:reset
インデックスの作成を終えれば、検索を行うための準備は終了です。
検索してみる
検索を行うための準備が整いました。
rails consoleを開いて、書籍を検索してみましょう。
# 本のタイトルで検索
> result = BooksIndex.query(match: {title: '<検索したい文字列>'})
> result.to_a
# 著者名で検索
> result = BooksIndex.query(match: {author: '<検索したい文字列>'})
> result.to_a
# 出版社で検索
> result = BooksIndex.query(match: {publisher: '<検索したい文字列>'})
> result.to_a
終わりに
とりあえず検索はできるようになりました。
細かい解説は今後少しずつ上げていこうと思います。
自分自身まだわからないところもたくさんあるので誤っている点など多々あると思いますが、ご指摘いただけると幸いです。
参考にした記事
https://github.com/toptal/chewy#installation
https://qiita.com/yamashun/items/6ecaa6f161b4cf283db3