More than 1 year has passed since last update.

はじめに

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

tsuwatch/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_indexupdate_in_indexdelete_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をさせていただいています。
ニコナレに少しでも興味を持っていただければなお幸いです :)