はじめまして。「病院なび」の開発チームメンバー甘利です。
国内最大級の病院検索サービス「病院なび」の改善にRailsエンジニアとして日々挑み続けております。現在 AWS Opensearch の導入を業務いて行なっています。少しずつ共有して行けたらと思っています。(※ この記事に具体的な手順等は含まれていません)
概要
自社サービスの 「病院なび」 に AWS Opensearch を導入するにあたり ”使いやすい仕組み” を目指して色々考えていきたいと思っています。「病院なび」 は主に Ruby on Railsで開発されていますので、便利な Gem で楽な実装ができると考えていました。ところが、AWS Elasticsearch から AWS Opensearch に変更になってしまい、巷にあるGemがそのまま使えなくなってしまい、楽ができなくなってしまいました orz。
現状、Opensearch を Rails から利用する際の選択肢として”公式コミュニティが公開している Ruby 用クライアントの利用”が比較的楽ですが、 Rails での利用を前提とした場合にはより効率的な仕組みを導入する必要があります。(いや、必要なくてもそうしたい)
そこで、 Rails+Opensearch 環境下で利用しやすい仕組みの実装を進めています。今回は手始めとして Index 管理のために、 Index の作成、削除、一覧参照の3つの Rake タスクを作成しました。Rails の DB migration 同様にIndexの定義ファイルを作成し、その定義ファイルを元にIndexを作成するような仕組になっています。これで少し便利になったと思います。(おもいたい)
「病院なび」に AWS Opensearch を導入したい理由
「病院なび」にはマップから医院を検索できる機能があります。実は既にこの情報を表示するために全文検索エンジン Groonga を利用していますが、以下の理由から AWS Opensearch に移行したいと考えています。
- 現状が導入方法により、メンテナンス性に課題がある。
- フルマネージドサービスであり柔軟にスケールが可能
また、将来的にフロントエンドから直接検索エンジンに接続できる能力を Openserch が有しているということも大きな理由です。
そもそも 「AWS OpenSearch」 とは?
AWS が提供しているマネージド全文検索エンジンです。もともと AWS は Elasticsearch を利用してマネージドサービスを提供していましたが、ElasticSearchのライセンスが ALv2 から Server Side Public License (SSPL) に変更されたのを期に、Elasticserch からフォークして Opensearch を立ち上げました。AWS が Elastic 社の制限を受けることなく、自由にサービスを提供するための選択をしたということですね。
実際に「病院なび」から「AWS Opensearch」に接続してみた
「病院なび」は Ruby on Rails で開発しています。それはつまり、巷にある Gem を利用して楽々実装できるということ!! ...と考えていた時期が僕にもありました。なんと、Elasticsearch で公開しているクライアント Gem に Opensearch への接続をブロックするコミットが積まれました。そのライブラリに依存している便利な Gem が使えなくなりました。 ほんとやめてほしい orz
そんなわけで、Opensearch が公開している Gem を利用していきたいと思います。
こちらの Gem はインスタンスを作成したタイミングで Opensearch への接続情報が用意され、メソッド呼び出しに応じて各 API がコールされるという、 REST クライアントとして一般的な作りの使いやすい(と感じる)ものでした。細かな方法については用意されているサンプルコードをご覧ください。
とはいえ、、、
もっと楽したいよね
これは REST の API すべてに共通することですが、汎用性が高い反面、指定項目が多くなったり、ステートレスのデメリットが目立ったりと、利用が面倒なことがあります。(と思ってます)そこで利用ケースを絞って使いやすい Rake タスクを作っていきたいと思います。
Rakeタスクを作ってIndexの操作で楽をしよう
手始めとして Index 管理のために、 Index の作成、削除、一覧参照の3つの Rake タスクを実装していきたいと思います。
Index 作成
既存の Groonga のデータ構造を Openserch に移植する想定で Index を作成してみます。以下の様な感じのリクエストボディになりました。ちょっとながかったので、中略して載せています。
{
"mappings": {
"properties": {
"address": {
"type": "text"
},
"city": {
"type": "text"
},
"county": {
"type": "text"
},
"geo_point": {
"type": "geo_point"
},
・
・
中略
・
・
"tel": {
"type": "text"
},
"update_at": {
"type": "date"
}
}
},
"settings": {
"index": {
"number_of_shards": 4
}
}
}
当然、上記のリクエストはリポジトリで管理しないわけにはいきません。このリクエストをテキストファイルに保存して、利用の度にコピペしてインデックスを作成したいというのであれば自由ですが、私はやりたくありませんきっと Ctrlキー を押す小指が大変なことになってしまいます。そんなわけで、JSON ファイルとして保存し、 Rake タスクではファイル名を指定して楽々作成される様にしたいと思います。
JSON ファイル を配置するディレクトリは rails_root 配下の db あたりにディレクトリを作成して配置するで良いかなと思います。 割と適当ですが、異論は認めません(助言は求めます)
rails_root
└── db
└── open_search
└── clinic.json
ファイル名を引数として以下の様に実行するとインデックスが作成される create_index タスクを作成しました。(日付をサフィックスとして付与しているのは Alias を使って運用を楽にするための準備です)
❯ rake "db:open_search:create_index[clinic]"
インデックス: cilnic_20220418-170821 を作成しました。
index 一覧参照
作ったものは確認したくなりますよね。ということで index_list というタスクで参照できる様になっています。
❯ rake db:open_search:index_list
.kibana_1 => .kibana
clinic_20220411-181733 =>
clinic_20220411-181818 =>
clinic_20220413-184844 =>
clinic_20220418-170821 =>
このタスクの実行結果では Index 名とそれに対応する Alias 名が表示されます。
index 削除タスク
Index 作成の際にサフィックスを付与しているため、作成タスク実行の度にIndexが増えていってしまいます。
消せないのも困りものですので、Index を削除するための delete_index タスクも用意いしました。
❯ rake "db:open_search:delete_index[cilnic_20220418-170821]"
corp_20220425-210817 を削除しました
以上で、Index の作成、削除、一覧参照がひとまず実現されました。
まとめ
今回は Opensearch を Rails で利用するための第一歩を踏み出しました。
次回以降は Alias の操作や Document の登録などについて書いていきたいと思います。
少しでも面白いと思っていただけたら LGTM お願いします
また、続きが気になるようでしたらフォローいただけると幸いです。