はじめに
2015年10月25日のニコニコ超パーティー2015で発表されたプレゼン共有サービス「ニコナレ」(詳しくはこちら)では、AWSのサービスを主に使用しており、本AdventCalendar1日目の記事で紹介されているメディアストレージ基盤を使用しています。
その他にも、検索システムとしてAmazon CloudSearchを使用しています。
ニコナレはRailsで開発を行っており、今回つくったCloudSearchを使用するための探し物を探し当てる程度の機能を持つGem、tsuwatch/nazrinの元となるライブラリが使用されています。
【追記】現在はニコナレ本番環境に導入されています
既存のGem
CloudSearchのGemを探したところ、すでにいくつかのGemが存在しています。
などです。
またRails(ActiveRecord)と連携できるGemの候補としてasariというGemがありましたが、以下の理由により、使用することを控えさせていただきました。
- aws-sdkを使用せず、エンドポイントへリクエストを直接書いている
- CloudSearchのインデックスに登録できる値が、必ずレコードの値でなければならず、自分で値を操作できない
- CloudSearchのインデックスに登録、更新、削除するタイミングが固定されている
- ActiveRecordへの
find
時にeager_loadingなどができない
などの点により、無理に使うくらいならということで自作することになりました。
Nazrin
使い方
Railsで
$ bundle exec rails g nazrin:config
とするとinitializers以下に下記のファイルが生成されます。
Nazrin.configure do |config|
config.debug_mode = false # trueにするとindex登録しなくなる
config.search_endpoint = ''
config.document_endpoint = ''
config.region = ''
config.access_key_id = ''
config.secret_access_key = ''
# currently support kaminari or nazrin
config.pagination = 'kaminari' # Nazrinから返却される配列がkaminariの配列になる
end
モデル内では以下のように使用します。
class Post < ActiveRecord::Base
include Nazrin::ActiveRecord::Searchable
searchable do
fields [:content]
field(:created_at) { created_at.utc.iso8601 }
end
after_create :add_to_index
after_update :update_in_index
after_destroy :delete_from_index
end
searchable
メソッドが生えるので、その中でCloudSearchのインデックスに登録するフィールドについての定義を書くことができます。
fields
メソッドで指定された配列(カラム名)は、CloudSearchのインデックスに作成されている同名のフィールドに、対象のレコードの値が保存されます。
またfield
メソッドを使用することで、Post
モデルのインスタンスをレシーバとして、任意の値をインデックスに登録することができます。(ちなみに上記の例のようにcreated_at(date field)はIETF RFC3339でなければならないので注意)
add_to_index
、update_in_index
、delete_from_index
はそれぞれCloudSearchで追加、更新、削除するメソッドとなっています。インスタンスメソッドなのでいつでも任意のタイミングで実行することができます。
また、検索するにはsearch
メソッドを使用し以下のように
Post.search.size(1).start(0).query("(and 'content')").query_parser('structured').execute
=> [#<Post id: 1, content: "content">]
することでCloudSearchから検索し、取得したものをActiveRecordで引き直します。
結果の配列は、設定により、kaminariもしくは独自実装の配列が返却されます。
また、
Post.search(includes: :hoge).size(1).start(0).query("(and 'content')").query_parser('structured').execute
とすることで、ActiveRecordで引き直すタイミングでeager_loadingしたり、Post.search(where: { status: :opened })
としたり、実行時に追加で実行したいActiveRecordのメソッドを指定することができます。
検索に関しては、aws-sdkを軽くラップしたものになっているので、query_parser
の設定など適切なクエリを投げる必要があります。
#さいごに
拙作tsuwatch/nazrinの開発を行いました。
AWSのGemは開発するのにお金を払う必要があり、厳しいものがありますね…。
これだ!というデファクトスタンダード的なGemもそれほどなくて結構困りものです。
RailsでCloudSearchを使うのであれば、オススメできるGemになっていると思います。ご検討いただければ幸いです。
ドワンゴは、RubyKaigi 2015でPlatinum Sponsorをさせていただいています。
ニコナレに少しでも興味を持っていただければなお幸いです :)