4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RailsアプリにElasticsearchを組み込む

Last updated at Posted at 2020-10-04

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モデルの検索周りの処理を作ります。

article-m/app/models/concerns/article/searchable.rb
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します。

article-m/app/models/article.rb
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がクエリを投げてくれます。

コントローラーは以下のようになります。

article-m/app/controllers/articles_controller.rb
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を組み込むのにやったことまとめ

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?