はじめに
株式会社ONE COMPATHのマサキと申します。
社内の各サービスで利用されている共通基盤となる検索システムを主に担当しております。
今回は、Solrベースの検索システムをOpenSearchを使ったシステムへリプレイスした内容について紹介いたします。
前提知識
移行前後の全文検索サービスについて記載します
Apache Solr
Solrとは、Apache Luceneをベースとしたオープンソースの高速な検索プラットフォームです。
高速に大量データをインデックス化することができ、全文検索やファセット検索、ハイライト表示など高度な検索機能を提供します。
当社では2009年頃から採用し、十数年にわたって使用してきました。
Amazon OpenSearch Service
オープンソースの検索・分析エンジンのOpenSearchをデプロイ、運用、スケーリングなど簡単に行える、AWSが提供するマネージドサービスです
OpenSearchは、Elastic社のElasticsearchを元にしており、ライセンス変更に伴い、AWSがフォークしてApache 2.0ライセンスを維持して開発を続けています
当社では、それまで空間検索などでElasticsearchの利用はありました。
リプレイスまで
リプレイス前の構成と問題についてご説明します
以前の構成
古いSolrベースの検索システムは長年データセンターで運用されてきましたが、数年前AWSへ全面的に引っ越しました。しかし、移行期間とリソース不足の問題から、オンプレミス時代のそのままの構成で移行したため、クラウドサービスの利点をあまり活かせておらず、EC2主体での構築となっておりました。
- ① Solrの元となるデータ
Amazon AuroraのPostgreSQLやMySQLなど利用しています。様々なデータソースを扱うため、外部API群や入稿ファイルなどからDBに登録していますが、それぞれ形式が異なるため、バッチ処理で形式を合わせて登録実行しています。特にサービスの性質上、位置情報に関する処理が多くなっています。- 同じデータが重複しないよう、名寄せや位置情報等でマージ
- 住所または緯度経度のいずれかがない場合は、自前のジオコーディング、リバースジオコーダで検索して付与(日本測地系)
- ② マスタSolr
データベースが更新されたことを検知すると、インデックスを作成します。作成したインデックスは各スレーブSolrへリプレケーション機能を使って配布。- 独自改修したSolrのDataImportHandlerでインデキシング
- 一部外部APIのみ、直接1件ずつSolr Update/Deleteで登録・削除 (図の※1)
- ③ スレーブSolr(マルチコア)
実際にユーザーが参照しているのは、スレーブSolrと同サーバにあるSolrを拡張して独自実装を加えたAPIです。以下は主な機能内容となります- スレーブSolrのインデックスをマルチコアとして検索
- サービスから最適な検索ができるよう、独自パラメータを追加し、特殊な検索仕様を追加
- 独自レスポンス形式を追加し、位置情報の測地系やエンコードも変更可能
- 一部機能では高速化のためDB(MySQL)からメモリ上にデータを保持。また直接DB検索も実施
古いシステムの問題点
1. バージョンアップが容易でない
上記の説明でもありますが、独自実装が複雑になりすぎて簡単にバージョンアップができない状態でありました
サービスを良くしようと最適な検索を実現するため、改造を繰り返しことにより、バージョンアップするのに大変な時間がかかっていました
2. メンテナンス性に乏しい
構成がモノリシックで、Solrと関係のない機能を追加していて、メンテナンスや拡張が難しい状態でした。
3. 急なアクセス増の対応が大変
アクセス増等による高負荷に対しては、手動でEC2のスタンバイ機を立ち上げて対応していました。 (図の※2)
スタンバイ機もマスタSolrから最新情報を配布されるまで時間がかかり、そこからロードバランサー(ELB)に投入というかなり手間のかかる作業を実施していました。
そのため、普段からEC2サーバはかなり余力のあるインスタンスを使っており、これがインフラコスト増にもつながっていました
リプレイスへの施策
新しいシステムへの移行検討と、最終構成について説明します
全文検索サービスの選定
長年使い続けたApache Solrですが、今後も使い続けるかを検討するにあたり、同じApache LuceneベースのElasticsearchとAmazon OpenSearch Serviceで機能比較をしてみました。
| 項目 | Apache Solr | Elasticsearch | Amazon OpenSearch Service |
|---|---|---|---|
| 開発元 | Apache Software Foundation | Elastic社 | AWS |
| 主な特徴 | 全文検索に重きを置き、 ドキュメント志向の検索アプリケーションに適している | リアルタイム分析、時系列データ、ログ分析に最適 | リアルタイム分析、時系列データ、ログ分析に最適 |
| 分散処理 | SolrCloud・zookeeperで対応 | 標準で分散対応 | 標準で分散対応 |
| クラウド対応 | 自前で構築 | 自前で構築 | AWSがマネージドで提供 |
| スケーリング | SolrCloudで手動/自動 | 自動(クラスタ構成) | オートスケール |
| REST API | 対応 | 対応 | 対応 |
| 管理UI | Admin UI | Kibana | OpenSearch Dashboards |
| 標準レスポンス | XML、JSON、CSV、PHP、Ruby、Python、Javabin等 | JSON | JSON |
| マネージドサービス | なし | ElasticCloud(有料) | AWSが提供(有料) |
一般的にSolrは学習コストが高いと言われているようですが、慣れ親しんでいることもあり、それほど不便は感じていませんでした。
しかし、インフラチームや開発メンバとの協議の結果、以下の点が優位ということで現在利用している AWSのマネージドサービス、OpenSearch Serviceを選択 することになりました
- サーバ等の運用・保守の容易さ
- インフラのオートスケール、バックアップ、障害発生時の自動復旧
- バージョンアップやセキュリティアップデートの自動化
形態素解析の変更
Solrでは、形態素解析のプラグインとしてKuromojiを利用していましたが、辞書のメンテナンスの問題もあり、こちらも見直しました
| Kuromoji | Sudachi | |
|---|---|---|
| 説明 | 形態素解析ライブラリ | Work Applications社の高機能な日本語形態素解析エンジン |
| 言語 | Java | Java、Python |
| 特徴 | シンプルで軽量、導入が容易 | 複雑な語彙や表記揺れ、複合語の解析に強い |
| 辞書 | IPA辞書ベース(標準的な日本語辞書) | IPA辞書ベース+独自拡張辞書(固有名詞や新語に強い) |
| 歴史 | 長年の実績あり | 比較的新しいため、最新の知見が反映? |
ちょうどAWSの OpenSearch ServiceでもSudachiプラグインが採用された時期だったため、比較的新しく辞書も定期的にメンテナンスされているSudachiを採用しました。
入力仕様の移行対応
SolrとOpenSearchでクエリが異なります。更に独自パラメータも多数追加していました。
- クエリ記述方法
- Solr
- URLパラメータ形式
- Lucene構文 (例
q=field1:aaa AND field2:bbb)
- OpenSearch
- JSONベースのリクエストボディ (例
{"query": { "match": {"field": "aaa"}}}) - DSLで柔軟な条件指定
- JSONベースのリクエストボディ (例
- Solr
クエリ解析については、構文解析ツールをANTLRを使ってOpenSearchのクエリを生成し、既存仕様に合わせました。
-
ANTLRとは
- 構文解析器や字句解析機を自動生成するツール(パーサジェネレータ)です。プログラミング言語やDSL、クエリなどの文法定義からテキストを解析するためのコードを生成することができます
新しい構成の検討
全体的にAWSサービスを活かした構成に変更しました
- API
- AWS ECS on Fargate
- バッチ処理
- AWS Batch、Lambda + Step Functions、EventBridge
- データベース、ストレージ
- OpenSearch Service、DynamoDB、S3
-
① 登録ファイル作成バッチ
OpenSearchへ一括登録(BulkAPI)できる形式でファイルを作成する独自のバッチ処理を実装しました。作成したファイルはS3バケットに配置します。以下の点から、厳密な構成が難しく、ここだけはEC2にバッチを載せることにしました。- インデックス作成時に空間検索を実施し、情報を付与する必要があった
- データ形式が異なり、タイミングや頻度も一定せずバラバラだった
- 大量データを全件更新する場合は、作成に時間がかかり、切替のタイミングをあわせるのが難しい
-
② ③ OpenSearchへのデータ登録バッチ
①で作成されたファイルは特定ルールの名前でS3バケットに配置されると、これをトリガーにOpenSearchへの登録バッチが起動します。S3バケットは、バージョニングを設定して、失敗時に過去のファイルを調査できるようにしています
構成図では端折りましたが、実際には間にLambda、Step Functions等を配置し、バッチ実行のジョブ管理はDynamoDBを利用しています- Batch実行に失敗した場合はリトライ
- OpenSearchへの登録が成功・失敗すると、Slackで通知
-
④ ⑤ API
全文検索(OpenSearch)とAuroraの両方を検索する機能と、Auroraのみを検索する機能があったため、これを分割して別のAPIとして構築。EC2は廃止し、ECS化しました
またGithub ActionsでCI/CD環境を構築しました
上記のような構成にすることで、以下の通り問題解決が可能となりました
1 バージョンアップが容易でない
- 全文検索はマネージドサービスのOpenSearch Serviceへ移行することで継続的なバージョンアップが可能に
- Solrを拡張し、独自実装していたAPIを、新たに全文検索部分に依存しないような構成でAPIを新規作成。OSに依存しないFargateを採用
2 メンテナンス性に乏しい
- 全文検索を利用しない機能は別のAPIとして新規作成。これにより、改修等で切り出した機能への影響がない状態へ
3 急なアクセス増の対応が大変
- ECSへ移行したため、オートスケールが可能
- OpenSearchもWebコンソールからノード追加が可能
リプレイス時の課題
リプレイス時に以下のような問題がありました
OpenSearch Serviceは一時停止できない
数年前ElasticSearch Service時代に一時停止機能がなかったのは知っていたのですが、時間も経ったのでRDSのように一時停止できるようになっていると勝手に思っていたのですが、
AWSへ直接確認したところ(2023年末)、やはり一時停止はできない状態のようでした
開発機を準備したのですが、円安もあり、そこそこお高いサービスですので、長期休暇とかの間停止したかったのですが、それができない。
仕方がなく、以下の処理を自動で実施できるようバッチを作成しました。
- OpenSearchインデックスのスナップショットを作成し、OpenSearchを削除
- OpenSearchを作成し、スナップショットからリストア
ただし、起動時は一部手動でOpenSearchのダッシュボードからセキュリティ設定など紐づけしたり、インデックスのテンプレートを登録する必要がありましたが、起動・停止が容易になりました。
ステークホルダーが多すぎる
長年運用してきていたため、各サービスでこの検索システムを多く利用しており、影響を把握しきれませんでした。既存サービスになるべく影響がないよう、アクセスログやソースコードを調査して利用状況を洗い出しました。
- 出力レスポンスの精査
SolrではCSVやPHP、Rubyなど様々な形式が標準レスポンスとして提供されていましたが、OpenSearchは標準ではJSONのみとなっています。更に独自仕様のレスポンスも追加していたため、様々な形式への対応が必要でした。- 各サービスでの利用状況を調査し、どの形式が利用されているか整理し、移行が必要なもののみ対応し、Rubyなどは廃止。また、一部形式については、JSONなどに変更いただきました。
- サービス側でのSolrクライアントライブラリの利用
一部のサービスですが、Solrクライアントライブラリを利用して改造Solrを参照していたため、これらの改修しなければなりませんでした- 改修したものを提供し、各部署で修正していただきました
検証が難しい
やはり全文検索エンジンが異なることもあり、単純な比較できないものがありました。
旧システムでは、あやしいクエリでも何故か動いてしまっていたものもあり(これはよくない)、対応に苦労しました。
影響の少ないサービスから順に切り替えを実施し、問題を特定して改修を繰り返しました。
さいごに
各部署の協力もあり、なんとかOpenSearchベースの検索システムへ移行を進めることができました。
Solrですが、個人的には慣れ親しんでいましたし(OpenSearchのQueryDSLはなかなか慣れず...)、先人たちの知識の蓄積もありますし、マネージドサービスがあればそのまま利用したかったところです。
とはいえ、インフラチームの負荷を軽減できたことはプラスになったと思います
(以前は休日夜間対応していたものが減ってはいるような?)
また移行する中で、既に利用のないパラメータや機能を精査することできたので大変よかったです。

