Ruby on RailsでAWS CloudSearchを利用した検索機能を実装する
検索機能をWebサービスで用いるのは、一般的でしょう。検索と言っても、完全一致や部分一致など様々な要件があり、場合によってはインデックスが使えず、処理に時間を要してしまうことがあります。
今回は、簡単な設定で強力な検索機能を使うことができる AWS CloudSearch を利用して、検索機能を実装して行きたいと思います。
CloudSearchとは?
AWSが提供するマネージドな全文検索サービスです。簡単なマウス操作で検索ドメインを作成でき、全文検索や範囲検索など、様々な機能を用いることができます。
実際に作成していきます。
AWS SDKをインストールする
まずaws-sdkをインストールします。
# Gemfile
gem 'aws-sdk', '~> 3'
config情報も事前にinitializerで定義しておきます。
# config/initializers/aws.rb
Aws.config.update({
access_key_id: ENV["AWS_ACCESS_KEY_ID"],
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"],
region: ENV["AWS_REGION"]
})
CloudSearchにデータを登録する
続いてDBに定義している情報を CloudSearch に登録していきます。例として、Articleテーブル(カラム:id, title, author)を登録していきます。
事前にAWS Console 上で CloudSearch の検索ドメインの設定を行っておきます。(こちらについては別途紹介できればと思います。)
今回はバッチ処理で一括アップロードします。アップロードの上限は、「 10 秒ごとに 1 つ、バッチあたり 5 MB 」に制限されいるので、ある程度データを区切った方が良いでしょう。
※ endpointはダッシュボードのsearch-endpointを使用します。また登録する際にはidをベースに登録処理を行います。
# lib/tasks/update_cloud_search.rake
desc 'CloudSearchにArticle情報をアップロードする'
task :update_cloud_search => :environment do
client = Aws::CloudSearchDomain::Client.new(
endpoint: ENV['CLOUDSEARCH_SEARCH_ENDPOINT']
)
# 500件ずつ登録
start_id = 1
end_id = 500
increment = 500
loop do
articles = Article.where(id: start_id..end_id)
break if articles.empty?
upload_document = []
articles.each do |article|
upload_document.push(
{
type: 'add',
id: article.id,
fields: {
title: article.title,
author: article.author
}
}
)
end
client.upload_documents(
content_type: 'application/json',
documents: upload_document.to_json
)
start_id = start_id + increment
end_id = end_id + increment
end
end
bundle exec rake update_cloud_search を実行して、CloudSearchにデータの登録が完了しました。
CloudSearchを用いた検索機能を実装する
実際に登録したデータを用いて、検索機能を実装していきます。
検索対象が今後も増えることを想定し、AWSが推奨しているディープページ分割という方法を用いて実装していきます。
フリーワードを検索キーとして、titleとauthorを横断検索していきます。検索を行うと、このワードに一致・部分一致したArticleのidが返却されます。
※ 後にidでwhere検索を行いたいので、flattenで平坦化を行っています。keywordがnilの場合、500エラーが起こるので、制御が必要です。
def fetch_id_by_cloud_search(keyword)
cloud_search_hit_ids = []
client = Aws::CloudSearchDomain::Client.new(endpoint: ENV['CLOUDSEARCH_GOURMET_SEARCH_ENDPOINT'])
cursor = 'initial'
loop do
page = client.search(
query: keyword,
size: 10000, # CloudSearchの上限数
query_parser: 'lucene',
cursor: cursor,
return: 'id'
)
cursor = page.hits.cursor
break if page.data.hits.hit.empty?
cloud_search_hit_ids << page.data.hits.hit.map(&:id)
end
cloud_search_hit_ids.flatten
end
戻り値を用いて、ActiveModelに返却する場合は以下のようにします。
Article.where(id: fetch_id_by_cloud_search('田中'))
# 例
# Article id: 1, title: アフロ田中, author: のりつけ雅春
# Article id: 2, title: ホゲホゲ日記, author: 田中太郎
まとめ
AWS CloudSearchを用いて、検索機能を実装しました。ActiveRecordのメソッドのみでは、実装しずらい横断検索もCloudSearchを利用することで簡単に実装が可能です。
参考
https://docs.aws.amazon.com/ja_jp/cloudsearch/latest/developerguide/what-is-cloudsearch.html
この記事が気に入ったらサポートをしてみませんか?