Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DMMの検索システムをSolrからElasticCloudに移行した話

 DMMの検索システムをSolrからElasticCloudに移行した話

以下の検索技術勉強会で発表したものに、時間の都合で削ったスライドなどを追加しています。
https://search-tech.connpass.com/event/370754/

Avatar for 小山凌太

小山凌太

October 30, 2025
Tweet

Other Decks in Technology

Transcript

  1. © DMM.com 2 自己紹介 - 所属: - 2019/04 合同会社DMM.com 新卒

    - 2019/07 検索チーム - 主にクラウドインフラ担当 - 趣味: - ライブやイベントに参加すること - 聖地巡礼 - ラーメン etc 小山 凌太 (Koyama Ryota)
  2. © DMM.com 5 Solrの運用構成 - EKSで管理 - 検索と更新でクラスタ 分離 -

    更新用Solrから検索 用Solrにレプリケー ションでデータ同期 (10分に1回)
  3. © DMM.com 6 SolrのEKS運用課題 - ウォームアップ による再起動コスト - Solr Pod起動時に全Indexデータをメモリに読み込む必要がある

    - 1 Podあたり約10~12分程度の起動時間 → オートスケールさせられない (間に合わない) - EKSのKubernetesバージョンアップ - 3ヶ月に一度 、全クラスタ(環境数×indexer/searcher)で対応 - ノードグループをAZごとに分離しており、1AZずつローリングアップデー トしていた - 本番のsearcherクラスタでは約6時間かかっていた
  4. © DMM.com 8 移行方針: 絶対に満たすべき条件(Must) 移行先を検討する上での方針 - must: - 運用コストを下げられる

    - 既存のSolrを用いた検索システムより性能的に劣ることがない - Solrで提供していた検索ユースケースを満たすことができる
  5. © DMM.com 9 移行方針: できれば満たしたい条件(Should) 移行先を検討する上での方針 - must: - 運用コストを下げられる

    - 既存のSolrを用いた検索システムより性能的に劣ることがない - Solrで提供していた検索ユースケースを満たすことができる - should: - 性能面でのパフォーマンス向上 - 検索改善のための豊富な機能
  6. © DMM.com 10 選ばれたのはElasticCloudでした - 運用コストの低減: - マネージドサービス なので、EKSクラスタ運用から解放される -

    豊富なドキュメント - Solrと同じLuceneライブラリ : - 機能的互換性が担保されており、移行リスクが低い - Serverlessへの期待: - 将来的な負荷ベースのオートスケール で、運用コストを更に低減 - 検索改善の未来: - 検索エンジンの機能としてベクトル検索や機械学習 など利用可能
  7. © DMM.com 12 ElasticCloudの懸念点 - 検索と更新のクラスタを分散できない - CCR(Cross-Cluster Replication)という機能でレプリケーション自体 はできるが...

    - これはLeader側クラスタのTranslogをポーリングしてFollower側で 同じ操作を実施するもの - つまり、負荷の分散には繋がらない - ディザスタリカバリや地理的に近いポイントで検索させるための データ配置用
  8. © DMM.com 13 移行の流れ 1. Query調査 - SolrとESでは似たような機能でも微妙な差がある - 機能ごとに結果を比較しながら調査

    2. 実装 3. 本番ログを使用した機能試験 - Solrと結果を比較→差がなくなるまで繰り返す 4. 本番リクエストをミラーリングして性能試験 - 検索・更新のリクエストをミラーリングしてチューニング
  9. © DMM.com 15 差分例1: or と and が複合した検索結果 - 例:

    「アニメ or 声優 or キャラ and DVD」でヒット数に差が出た - 原因: - Solrでminimum_should_matchにあたる設定(mm)をしていなかっ た - 「アニメ or 声優 or キャラ and DVD」と「DVD」の検索結果が一緒 - 対応: - Solr側の設定ミスであり、あるべき姿はES側の結果なので、差分 を許容
  10. © DMM.com 16 差分例2: 0トークンが空集合として扱われる - 例: 「? and ?

    and アニメ」クエリでESが0件ヒット - 原因: - Solrではパース時点で「?」が除去されていたが、ESでは形態素 解析でも2gramでも空集合とみなされ、論理積を取ると0件になる - 対応: - 1文字の場合は2gramは通さず、zero_terms_queryにallを設定(こ れによって空集合ではなく全集合になる)
  11. © DMM.com 18 移行して良かったこと / 移行の成果 - 移行の成果: - ESのrerank機能+terms_lookupによるスコアリングで検索改善施策

    の中でも過去一の売上リフト - Solrの撤去によるEKS運用コストの削減 - EKSのアップデート工数が最大6時間→2時間に激減 - 学び: - 検索エンジンの仕組みへの理解が深まった - 例): - Luceneのスコアリングの仕組み - クエリからユーザの意図を把握する
  12. © DMM.com 19 移行後に発生した課題 - 問題:95%ileの平均レスポンスタイムは向上したが、特定の「スロークエリ」 でSolrより性能が悪化 - 原因:オブザーバビリティの不足 -

    性能試験での監視項目が全体監視に偏り 、サービス個別やIndex別、 スロークエリなど細分化された性能を見れていなかった - 対策: - プライマリシャード数のチューニング - index分離 → Deployment分離 - 1文字検索の要件見直し etc
  13. © DMM.com 20 施策:プライマリシャード数のチューニング - 元々性能試験時にプライマリシャード数 1 と 2 で比較はしていた

    - 性能試験段階では差はないと判断した が、改めて 5 まで増やして 性能試 験をしたところ改善効果が見られた
  14. © DMM.com 22 現在の最大の課題 - reindexによる運用負荷 - 既存のETLパイプラインとの相性の悪さから工程が複雑化 - Index

    Templateの変更に伴って頻繁に発生する - 一時的な対応として フィールド追加はIndex Templateの変更をし つつ、直接API経由で動いているIndexのMappingを更新するよ うにした - 性能課題 - 事業部によっては性能問題がシビアなところもあり、引き続き Deployment分離などで性能改善中
  15. © DMM.com 23 今後の展望 - 検索APIや更新システムなどEKSに残っているシステムをGoogle Cloudに 移行する - 移行するだけでなく、システム自体も見直すことでreindexなど、既存の

    課題にも対応予定 - Deployment分離による各サービスの性能改善と将来的なスキーマ最適化 - 更なる検索改善 - マッチング改善などもしていきたい
  16. © DMM.com 24 おまけ - 今回の発表内容は以下のブログにしているので気になった方はぜひ - https://developersblog.dmm.com/entry/2025/08/04/110000 - また、ElasticCloudについてFindy

    Toolsにてレビューを寄稿しています - こちらも気になった方はぜひ - https://findy-tools.io/products/elastic-cloud/1228/703
  17. © DMM.com 26 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 調査1: - Solrクエリをデバッグ - Solrでは「アニメ」の検索結果と一致 - 「?」はパース段階で除去されていた
  18. © DMM.com 27 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 調査2: - ESクエリを調査 - 前提: - DMMの検索では形態素解析用のjaフィールドと2gram用のcjk フィールドがある - 「?」はjaとcjkどちらのアナライザーを通しても空になり、論理積を取る と0件になる
  19. © DMM.com 28 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 対応1: - zero_terms_queryにallを指定する - これにより、空集合を全集合として扱うことができる - 「? and ? and アニメ」は全集合とアニメの論理積を取り、検索結 果がアニメと一致する
  20. © DMM.com 29 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 新たに発生した問題: - 「夢」のような1文字のクエリで検索したときに2gramの検索が全集合に なるため、全ドキュメントを返してしまう
  21. © DMM.com 30 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 新たに発生した問題: - 「夢」のような1文字のクエリで検索したときに2gramの検索が全集合に なるため、全ドキュメントを返してしまう - この問題の対応 1: - 「?* and ?* and アニメ」のように1文字の場合は前方一致検索にして 2gramでも通るように変更
  22. © DMM.com 31 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 新たに発生した問題: - 「夢」のような1文字のクエリで検索したときに2gramの検索が全集合に なるため、全ドキュメントを返してしまう - この問題の対応1: - 「?* and ?* and アニメ」のように1文字の場合は前方一致検索にして 2gramでも通るように変更 - 更なる問題: - 前方一致検索は性能が悪く、検索がタイムアウトしまくる
  23. © DMM.com 32 Appendix: 0トークンが空集合として扱われる(詳細) - 事象: - 「? and

    ? and アニメ」クエリでESの検索結果が0件になる - 最終的な解決策: - 1文字検索の場合は2gram用のcjkアナライザーを通さず、形態素解析 のみでzero_terms_queryにallを指定する - cjkを通さないので、「夢」のような1文字検索も形態素解析でそのまま 検索でき、「?」のような意味のない検索は全集合になる
  24. © DMM.com 33 Appendix: reindexの複雑さ 1. Index Templateを変更 2. reindexを実施(ここで新しいindexも作られる)

    3. 新しいindexへの更新用ETLジョブを新しく作成 4. Kafkaのキューをreindex直前まで戻す 5. 新旧indexの更新が同期されるまで待つ 6. 検索用エイリアスに紐づくindexを新しいindexに張り替える 7. 古いindexへの更新用ETLジョブを削除 8. 古いindexを削除
  25. © DMM.com 34 Appendix: reindexの複雑さ 1. Index Templateを変更 2. reindexを実施(ここで新しいindexも作られる)

    3. 新しいindexへの更新用 ETLジョブを新しく作成 4. Kafkaのキューを reindex直前まで戻す 5. 新旧indexの更新が同期されるまで待つ 6. 検索用エイリアスに紐づくindexを新しいindexに張り替える 7. 古いindexへの更新用 ETLジョブを削除 8. 古いindexを削除 ←ここで手動操作  が入る
  26. © DMM.com 39 Appendix: reindexの複雑さ - 例えば、検索と同じエイリアスに更新を向けるとreindex手順は以下 - Index Templateを変更

    - 対象indexへの更新を一時的に止める - reindexを実施(ここで新しいindexも作られる) - エイリアスに紐づく indexを新しいindexに張り替える - 更新を再開する - 古いindexを削除
  27. © DMM.com 40 Appendix: reindexの複雑さ - 例えば、検索と同じエイリアスに更新を向けるとreindex手順は以下 - Index Templateを変更

    - 対象indexへの更新を一時的に止める - reindexを実施(ここで新しいindexも作られる) - エイリアスに紐づく indexを新しいindexに張り替える - 更新を再開する - 古いindexを削除 - reindexの時間次第だが、最悪かなりの時間事業部からの更新を止め ることになる
  28. © DMM.com 41 Appendix: reindexの複雑さ - だったら検索とは別に更新用のエイリアスを作る? - その場合の手順は以下 -

    Index Templateを変更 - reindexを実施(ここで新しいindexも作られる) - 更新用エイリアスに紐づく indexを新しいindexに張り替える - Kafkaのキューを reindex直前まで戻す - 検索用エイリアスに紐づくindexを新しいindexに張り替える - 古いindexを削除
  29. © DMM.com 42 Appendix: reindexの複雑さ - だったら検索とは別に更新用のエイリアスを作る? - その場合の手順は以下 -

    Index Templateを変更 - reindexを実施(ここで新しいindexも作られる) - 更新用エイリアスに紐づく indexを新しいindexに張り替える - Kafkaのキューを reindex直前まで戻す - 検索用エイリアスに紐づくindexを新しいindexに張り替える - 古いindexを削除 - Kafkaのキューが最新に追いつくまで結局更新が止まる