OpenSearchでレガシーな検索処理の大幅改善をやってやろう
by
DPon
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
OpenSearchでレガシーな検索処理の 大幅改善をやってやろう PHPカンファレンス小田原2025
Slide 2
Slide 2 text
自己紹介 ● 堂薗 伸樹(どうぞの のぶき) / DPon(@DPontaro) ○ 園 薗 ● 職業:エンジニア ● 所属:スターフェスティバル株式会社 ● 家族:妻 子👦👦 犬 ● ゲーム好き ● 大阪からきました ● 🎉 カンファレンス初登壇 🎉
Slide 3
Slide 3 text
会社とサービスの話 ● https://gochikuru.com/ ● 法人・団体向けの宅配弁当 ケータリング・オードブルの デリバリーサービス。
Slide 4
Slide 4 text
前段 プロジェクトの説明
Slide 5
Slide 5 text
プロジェクトの特徴 ● ごちクルとは別の特定業界向けのお弁当デリバリーサービス ● Initial Commitは2015年 ● コロナ禍で需要減。リソース都合もあり、しばらく専任のエンジニアがついていない 状態。 ● ときどき改善依頼があった際、手が空いてる人がスポットでアサインされる
Slide 6
Slide 6 text
パフォーマンスの課題 ● 2024年春、サイトのパフォーマンスは少し触れただけでも体感できるくらいに悪い ● 需要が戻りつつあるなか、マイナスの印象を与えるわけにもいかない
Slide 7
Slide 7 text
レガシーな環境
Slide 8
Slide 8 text
初手の改善
Slide 9
Slide 9 text
ボトルネックをみつける 商品検索のController。 リクエストされる頻度高く、かつ重い ページ。 中央値が 1.9 sec これに加え、ページ表示までに画像や cssのダウンロードなども発生する
Slide 10
Slide 10 text
初手の改善 スロークエリに手を入れてみる ● INDEXの追加 ● 該当箇所のコードを調整し、発行されるクエリを修正 結果200msec くらいは改善したが焼け石に水。
Slide 11
Slide 11 text
さてどうしたものか 長年専任がついていないプロジェクト、コードはツギハギで無駄も多い。 複雑に絡み合ったコードの解消のために、検索ロジック全体を組み直す必要がありそ う。 → それならもう OpenSearch に移行してもいいのでは?
Slide 12
Slide 12 text
OpenSearchとは ● 分散型の検索エンジン。Elasticsearchのフォーク版 ● クラスタ構成、複数のノードにデータ分散。 ● 高速な全文検索が可能
Slide 13
Slide 13 text
簡単に用語解説:Document ● Document:データを格納する単位。JSON形式。 ○ 学生のデータベースでは、 Documentは1人の学生を表せる ○ RDBにおける行に相当
Slide 14
Slide 14 text
簡単に用語解説:Index ● Index:Documentの集まり ○ RDBでいうテーブル ○ 学生のデータベースでは、 Indexはすべての学生を表す
Slide 15
Slide 15 text
簡単に用語解説:Clusterとか ● Cluster, Node ○ Clusterは、Nodeの集まり。 ○ Nodeはデータを保存、検索リクエストを処理 するサーバ。 ● Shard ○ いわゆる水平分割。 ○ Indexのdocumentを行単位でシャード分割し て分散 ○ シャードの分割目安:シャードのサイズを 10 ~ 50 GB に制限することです。(公式いわく)
Slide 16
Slide 16 text
OpenSearchへの移行
Slide 17
Slide 17 text
OpenSearch公式のPHPクライアント まぁバージョン下げたら対応してるやつあるやろ。 https://github.com/opensearch-project/opensearch-php
Slide 18
Slide 18 text
おっかしいなー
Slide 19
Slide 19 text
真面目にどうするか 理想はPHPのバージョンアップ。そうはいっても ● スポット的なアサインでもあり、メインは別プロジェクトの人員 ● 元のミッションはパフォーマンス改善。 →バージョンアップはスコープ外では? ● 認知負荷の高いコードの理解、スロークエリの対応など既にある程度時間もかけて いる。 →このタイミングからバージョンアップまでやる? ※言わずもがなテストはメンテされておらず
Slide 20
Slide 20 text
戦略的後回し // TODO PHPバージョンアップ 結局公式のPHP7.3が対応してるバージョンのクライアントを落としてから、7.1で動くよう にエラーが出る箇所をつぶして対応させました。 ※バージョンアップはパフォーマンス改善後に対応しました(7.4までですけど...
Slide 21
Slide 21 text
バッチの実装 毎時 RDS -> OpenSearch へデータ投入するバッチを実行。 その際”YYYYMMDD-HH”のサフィックスを持つINDEXが作成される。 例:product-index-20250412-15 INDEX作成後、アプリケーションが参照している OpenSearchのINDEXのエイリアスを変更。 実行前:product_index -> product-index-20250412-14 実行後:product_index -> product-index-20250412-15
Slide 22
Slide 22 text
マッピングの話 マッピングはOpenSearchに、ドキュメントとそのフィールドの保存方法とインデックスを指示します。 各フィールドのデータ型を指定することで (例えば、年を日付にするなど )、保存やクエリをより効率的に行うこと ができます。 Dynamic mapping (動的マッピング) 新しいデータやフィールドが自動的に追加される。 Explicit mapping (明示的マッピング) 推奨。正確な構造とデータ型を前もって定義できる。 パフォーマンスや正確性を高めることができる
Slide 23
Slide 23 text
マッピング一例 "id": map[string]string{"type": "integer"}, "product_name": map[string]interface{}{ "type": "text", "analyzer": "product_index_analyzer", "search_analyzer": "product_search_analyzer", },
Slide 24
Slide 24 text
analyze 文字列を検索に使えるように「分かち書き(トークン化)」&「正規化」する処理
Slide 25
Slide 25 text
analyzer と search_analyzer "product_name": map[string]interface{}{ "type": "text", "analyzer": "product_index_analyzer", "search_analyzer": "product_search_analyzer", }, analyzer:インデックス時(保存時)に使用する analyzer を指定。 search_analyzer:検索時に使用する analyzer を指定
Slide 26
Slide 26 text
synonym_filter search_analyzer には上記のsynonym_filterという同義語の設定がされている。 この設定により曖昧検索に対応できる "synonym_filter": map[string]interface{}{ "type": "synonym", "synonyms": []string{ "ウナギ,ウナジュウ", "子供,お子様",
Slide 27
Slide 27 text
やってみてどうだった
Slide 28
Slide 28 text
🎉結果発表🎉 before 中央値:1.9sec after 中央値:0.92sec
Slide 29
Slide 29 text
売上につながった? ここ1年で売上の数値はしっかり伸びている 🎉 複数要因があるものではありますが、パフォーマンス改善で下支えが出来た ※余談 社内の営業の方々から直接 DMでめちゃ助かったと何人か声かけていただいて、好感触
Slide 30
Slide 30 text
他改善するなら ● 毎時のバッチ実行 ○ 日々商品のデータは更新されているが、最大 1時間の遅延を許容している状態 ○ よりリアルタイムに更新したい場合、イベント駆動な仕組みを取り入れたり ● インフラのあいのり ○ ごちクルと同じインスタンスなので障害発生した際は、どちらも検索処理が機能しなくなる(今のとこ ろ発生はしていない) ○ 切り離せば懸念はなくなるが、コスト増にはなるのでバランス考えて ● synonym_filterなどがコード中に定義されている ○ 変更の際にエンジニアの手が入る状態となっているので、できれば外部ファイルに逃がしたほうが 良い