Elasticsearchとは
ElasticsearchとはElastic社が開発しているOSSの全文検索エンジンです。
大量のドキュメントから目的の単語を含むドキュメントを高速で抽出することができます。
RailsアプリでElasticsearchを扱う考え方
1.全文検索エンジンに検索対象のデータが入っている
2.アプリケーション側で検索すると、検索エンジンに対してクエリを発行し、結果が返却される
3.アプリケーション側で検索対象のデータが更新されると、連携して検索エンジンのデータも更新される
RailsアプリでElasticsearchを扱う
インデックスを作成する
Elasticsearchでは、データの保存場所としてインデックスを作成します。
リレーショナル・データベースでいうところのテーブルのようなものです。
まずは、RailsのモデルをElasticsearchでも扱うために専用のgemをインストールします。
以下をGemfileに記述し、bundle installします。
gem 'elasticsearch-model', github: 'elastic/elasticsearch-rails'
gem 'elasticsearch-rails', github: 'elastic/elasticsearch-rails'
bundle installが終わったら、Elasticsearchにインデックスを作成します。
検索対象としたいモデルの中で、Elasticsearch::Modelをincludeします。
class Article < ActiveRecord::Base
include Elasticsearch::Model
end
これでモデルでElasticsearchを扱う準備ができました。
インデックスは以下のようなコードで作成できます。
Article.__elasticsearch__.create_index! force:true
インデックスにドキュメントを入れる
Elasticsearchでは、インデックスに入っているデータのことをドキュメントと呼びます。
インデックスには検索対象にしたいデータを入れます。
以下のコードでElasticsearchにドキュメントをインポートします。
Article.import
これでElasticsearchのインデックスの中に、ドキュメントが登録されます。
ドキュメントを検索する
ドキュメントを検索するには、Elasticsearchにクエリを投げます。
以下のように書くことで、RailsからElasticsearchにクエリを投げることができます。
response = Article.search 'hoge'
引数で検索文字列を指定することで、ドキュメントを検索することができます。
フロントからパラメータを受け取って検索すると以下のように書けます。
def index
@articles = Article.search(params)
end
Rails側で検索対象のレコードが更新されると、それに伴ってElasticsearchのドキュメントも更新する
実際にサービスを運用するとなると、Rails側でレコードが更新されるとElasticsearchのドキュメントを更新する必要があります。
まず単にElasticsearchのドキュメントを更新するには、以下のように実装します。
Article.first.__elasticsearch__.update_document
他にも、delete_documentというメソッドがあるので、これを使えばドキュメントの削除もできます。
上記のように明示的に書かなくても、レコードを更新した際に自動的にドキュメントを更新することもできます。
gemであるelasticsearch-modelでは、Elasticsearch::Model::CallbacksをModelにincludeしておくと、レコードを更新した際にElasticsearchのドキュメントを更新するクエリを投げてくれます。
class Article
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
end
RailsアプリにElasticsearchを組み込む
実際にArticleモデルの検索周りの処理を作ります。
require 'active_support/concern'
module Article::Searchable
extend ActiveSupport::Concern
included do
include Elasticsearch::Model
index_name "article"
settings index: {
number_of_shards: 1,
number_of_replicas: 0
} do
mapping _source: { enabled: true } do
indexes :id, type: 'integer', index: 'not_analyzed'
indexes :title, type: 'string'
indexes :content, type: 'text'
end
end
end
module ClassMethods
def create_index!(options={})
client = __elasticsearch__.client
client.indices.delete index: "article" rescue nil if options[:force]
client.indices.create index: "article",
body: {
settings: settings.to_hash,
mappings: mappings.to_hash
}
end
end
end
モジュールの中で、include Elasticsearch::Modelして便利なメソッド群を使えるようにします。
index_nameはインデックス名、settingsにはインデックスの設定を書きます。
number_of_shardsやnumber_of_replicasはシャードやレプリカの設定で、耐障害性や性能に関連します。
mappingはインデックスをどのように定義するか決めます。RDBでいうテーブルスキーマのようなものです。
create_index!は実際にインデックスを作成するヘルパーです。
elasticsearch.clientでElasticsearchのクライアントのオブジェクトが取れるので、
このクライアント経由でいろいろ操作できます。
作ったモジュールをモデルにincludeします。
class Article < ActiveRecord::Base
include Article::Searchable
def self.search_message(keyword)
if keyword.present?
query = {
"query": {
"match": {
"message": keyword
}
}
}
Article.__elasticsearch__.search(query)
else
Article.none
end
end
end
もらったキーワードから検索のクエリを組み立てて、Article.elasticsearch.searchに渡します。
Articleモデルに対して__elasticsearch__.searchを呼び出すことで、elasticsearch-railsとelasticsearch-modelがクエリを投げてくれます。
コントローラーは以下のようになります。
class ArticlesController < ApplicationController
def search
@keyword = params[:keyword]
@articles = Article.search_message(@keyword).paginate(page: params[:page])
end
以上がRailsアプリにElasticsearchを組み込む一例です。
参考
elastisearch-railsを使ってRailsでElasticsearchを動かす【初心者向け】
Railsアプリの検索処理にElasticsearchを組み込むのにやったことまとめ