はじめに
初めまして、株式会社スタンバイのジョブサーチメインというチームで検索エンジン周りの開発・改善に取り組んでいる金正です。
検索エンジンの改善施策の一環としてクエリオートコンプリーションシステムのリプレイスを行いました。
リプレイスに取り組んだ背景やアーキテクチャ、工夫したことなどをご紹介していきます。
クエリオートコンプリーションとは
クエリオートコンプリーションとは、ユーザーの入力から始まるキーワードをサジェストする機能になっています。
以下の例では「エンジニ」という文字列から始まるキーワードをサジェストしています。
以降ではクエリオートコンプリーションのことをQAC(Query Auto Completion)と略します。
スタンバイにおけるQAC
スタンバイでは、キーワード検索窓と勤務地検索窓の2つの検索窓が存在しています。
キーワード検索窓では、以下のように検索キーワードをサジェストします。
勤務地検索窓では、住所・駅のみをサジェストします。
サジェストされるキーワードに違いがあるものの、後述するシステム構成自体には特に大きな違いはないので、 後述するシステム構成等の項目ではキーワード検索窓、勤務地検索窓の両方の話をしているんだなと思っておいてください。
QACシステムリプレイスに取り組んだ背景
まずQACシステムのリプレイスに取り組んだ背景からです。 大きく以下のような課題がありました。
- 構築当時のエンジニアが社内に残っていない
- QACシステムに関するドキュメントがない
- QACシステムで利用しているデータやツール・ライブラリのバージョンが構築当初のままになっている
- QAC以外のデータも同居しているためシステムの分離ができていない
以上のように手が付けられない状態です。 既存QACシステムを改修するよりも、新しく作成しリプレイスする方が工数的にも少ないと判断し取り組み始めました。
現状のQACシステムの課題
現状のQACシステム構成は下図のようになっていました。
サジェストするデータを含んだElasticsearchのコンテナイメージを作成しECSにデプロイすることでQACを実現しています。 このアーキテクチャと前述した背景の詳細課題を列挙すると以下のような課題がありました。
課題点 | 詳細 | |
---|---|---|
1 | EMRで動かすスクリプトがメンテされていないので動かない | データ元のログのフォーマットやEMR自体の更新がされていないのでEMRを動かそうにも動かせない状態 |
2 | 自動化されていない | インデックス更新からデプロイまで手動で行う必要がある |
3 | Elasticsearchのバージョンが2系 | QACシステム開発当初のElasticsearchのバージョンのままになっておりセキュリティリスクがあり非常に危険 |
4 | データ更新ができる状態ではないので、最新の検索キーワードに対応できていない | 例えば、コロナと入力してもサジェストキーワードが何も表示されない |
5 | データ元が不明 | 勤務地サジェストのためには、全国の住所・駅データが必要だが、これも更新されていないので市町村合併や名称変更に追従できていない |
6 | ログが落ちていない | ユーザーの入力キーワードや、そのキーワードに対してどのようなサジェストキーワードを掲出したか等、分析するためのログが落ちていないので改善施策を回すことができない |
QACのシステムアーキテクチャ
上述した課題を根本的に見直すために全システムの構成を一から見直しました。
まず最初に取り組んだのは、基幹となる検索エンジン部分の技術選定です。
QACシステムを構築する上での要件として以下のような要件がありました。
タイプ | 要件 | 詳細 |
---|---|---|
システム要件 | シャーディングは不要だが、レプリケーションが必要 | インデックスのデータ量は少なく(大体100MBほど)分散検索は不要だが、負荷分散や耐障害性の向上を目的としたレプリケーションが必要となる |
システム要件 | 最小限の構成 | 検索機能が最小限であり、QACを実現するために必要な機能があること |
ビジネス要件 | ユーザー入力キーワードを日本語かな・漢字、ローマ字のいずれにも対応する | 例えば、「とうk」とキーワード入力した際には、「東京」「東急」など「とうk」から始まるキーワードを掲出させる |
ビジネス要件 | 複合語にも対応 | 「エンジニア ふk」とキーワードを入力した際に、「エンジニア 副業」「エンジニア 副業 週一」などのように2つ以上のキーワードも掲出させる必要がある |
しかし検索エンジンといっても世には様々な検索エンジンが存在しています。
社内では他システムの検索エンジンとしてElasticsearchを利用している実績があります。
ですので、主にElasticsearchとその内部で利用されている検索エンジンライブラリであるLuceneの2つの候補が上がりました。
上記の要件を満たす前提で各検索エンジンのメリット・デメリットをまとめると以下表のようになりました。
メリット | デメリット | |
---|---|---|
Luceneベース | ・最新のLuceneに更新しやすい ・一つの機能(QAC)に特化した検索エンジンを構築できる ・システム構成が簡潔 ・トークンフィルタをカスタマイズ作成・利用可能(ローマ字変換等々) |
・スケールアウトしにくい(データ量が増えた際に自前でクラスタリングを構築する必要がある) ・API層を自前で作成する必要がある |
Elasticsearchベース | ・柔軟性がある(設定オプションが豊富でカスタマイズしやすい) ・ドキュメントが豊富 ・スケールアウトしやすい ・トークンフィルタをカスタマイズ作成・利用(ローマ字変換等々) |
・最新のLuceneにすぐに対応できない(Elasticsearchのバージョンアップを待つ必要がある) ・前段のAPIサーバとElasticsearchのサーバ2台構成になるのでよりコストがかかる ・QAC以外の機能も備えているので余分な機能も存在する |
トークンフィルタを駆使すれば、ビジネス要件としてはLuceneベースでもElasticsearchベースでも満たすことが可能だとわかりました。
システム要件の以下2点でLuceneベースの検索エンジンを構築することに決定しました。
- より軽量な構成(QACに特化した検索エンジン)
- Elasticsearchなどの検索エンジン側の対応を待たずに、最新のLuceneへ更新できる
以上の決定を踏まえた最終的なシステムアーキテクチャは以下のようになっています。
INDEXワークフローとQAC-APIの2箇所でLuceneを利用しています。
新システムアーキテクチャのメリット
検索エンジンのコンピューティング(以下、検索)とストレージ(インデックス)を分離したアーキテクチャにしています。 具体的には
- インデックスをS3のようなストレージに格納
- 検索時にはそのストレージに格納されたインデックスをダウンロードし、検索を走らせる
このようなアーキテクチャにすることによって以下のいくつかのメリットが考えられます。
メリット | 詳細 |
---|---|
インデクシング・検索のスループット向上 | CPU負荷の高いインデクシングが一度だけ行われるので、分離しないものと比較してインデクシングのスループットが向上 |
インデックスのバージョニングが可能 | インデクシングごとに、作成されたインデックスをストレージにアップロードするタイミングでインデックスのバージョニングが可能 またインデックスのバージョンを変更する必要がある場合、インデクシングや検索システムに影響を与えることなく切り替えることが可能 |
メンテナンス性の向上・スケーラビリティの向上 | 両方のプロセスを独立してスケールさせることができる 例えば、インデクシングを行うシステムをアップグレードする場合、検索システムには影響は与えない |
施策の並列実施 | ランキングロジック変更等でインデックスを変更する場合、検索システムに影響を与えることなくインデクシングが完了できるので、さまざまな施策の並行稼働が容易に |
この検索とインデクシングを分離するアーキテクチャの考え方は、ElasticsearchやAWS OpenSearch(Elasticsearchをフォークしたサービス)でも提案されています。
それぞれのシステムの詳細
次に検索エンジン以外のシステムの詳細を説明します。
ワークフロー自体はairflowで管理するなど、極力管理する工数を削減するために基本的にマネージドなAWSサービスを利用したアーキテクチャにしています。
ETLワークフロー
以下のようなシステム構成になっています。
アーキテクチャ図左端のS3に格納されているリクエストログを元に、下記に挙げる処理をETLワークフローで行います。
- 記号などの検索に用いるキーワードとしては不適切なキーワードまたは文字の削除
- 良俗公序に反するNGキーワードの削除
- タイポと思われるキーワードのリライト など
実際にユーザーが入力・検索したリクエストログをもとにサジェストキーワードを生成するので、検索窓に適切なキーワードが表示されるように処理を行っています。
INDEXワークフロー
以下のようなシステム構成になっています。
上述したETLを行ったデータから、Luceneのインデックスを作成するワークフローになっています。
ECSの部分は他に、AWS GlueやAWS lambdaと候補があったのですが、コストや利用したいLuceneのバージョンなど様々な制約があったので比較的柔軟に単発バッチを実行できるAWS ECSで構成することにしています。
Luceneのトークンフィルタと自前のトークンフィルタを駆使してのインデックス構築します。
詳細は省きますが、例えば「看護師」というキーワードに対して以下ようにedge-ngram分割・ローマ字変換などの処理をし、インデックスを構築しています。
original_text: 看護師 suggest_text: 看 看護 看護師 k ka kan kang kango kangos kangosh kangoshi
より詳細を知りたい方は以下の記事を参考にしてください。 スタンバイアドベントカレンダー2022向けに書いた記事
QAC-API
以下のような使い方をしています。
- サーバ起動と同時に、INDEXワークフローで作成したLuceneのインデックスをダウンロードする
- ユーザーの検索文字列に対して、ローマ字検索するためにLuceneのトークンフィルタなどを活用している
- ユーザーの入力文字列に対して、Lucene インデックスに検索をかけるだけの非常に薄い構成のAPI
- インデックスのサイズが平均で100MBほどなので、Elasticsearchなどのようにシャーディングせず、一台のサーバのメモリ上に乗せている
性能
99パーセンタイルで、1.5msほどのレイテンシでサジェストキーワードを返せています。
インデックスのデータ量は旧QACシステムと比べて増加しているのにも関わらず、旧システムの15msと比べると10倍ほど早くなっています。
新旧で利用しているそれぞれの検索エンジンのバージョン以下のようになっています。
- 旧QACシステム:Elasticsearch 2.3.5
- 新QACシステム:Lucene 9.3.0
パフォーマンスが上がっている理由としては以下が考えられます。
- サーバのCPUコア数が2倍になった
- 旧システムでは2vCPUに対して、新QACシステムでは4vCPUに増やした
- サーバにはAWS ECSを利用しているが、利用できるRAMサイズとの関係でCPUコア数を2倍に増やしている経緯がある
- QACだけで使われるようになたのでシンプルにリクエスト数が減った
- 旧システムでは、QACの用途以外でも利用されていたコンピューティングリソースをQACの用途だけで使えるようになった
- Luceneを直接利用することで、レスポンスを返すまでの処理量が減った
- 旧システムではElasticsearchにカスタムプラグインを組み込んでQACを実現していたので、処理が多数走っていた
運用
上記で説明してきた ETL・INDEXワークフロー、QAC-APIのデプロイ全てを全自動で行っているので、基本的に運用工数はかからないようになっています。
またインデックスの更新頻度は以下表のようになっており、毎日最新のQACサジェストキーワードを表示できるようになりました。
- インデックス更新頻度: デイリー
- インデックスデータ元:過去1日分のログから
評価
新システムへのリプレイス実施を判断するため、「QACの質」と「サービス全体への影響」の2軸で旧システムとの比較評価を行いました。
QACの質
QACシステムの品質は「できるだけユーザー入力の手間を省いて、意図する検索キーワードを表示できていること」と言うことができます。
これを言い換えるとつまり、
「ユーザーの検索窓への入力数が少なく、表示されたQACサジェストキーワードのクリックが増えていること」
上記を構成する指標が以下の2つの指標になっています。
- QACサジェストキーワードのクリック率
- QACサジェストキーワードのカバレッジ
サービス全体への影響
QACシステムの質だけではなく、スタンバイのサービス全体にとってどう影響があるのかも確認する必要があります。
スタンバイでは主に求人クリックと応募を指標として追っているので以下2つの指標を確認しています。
- QACサジェストキーワードをクリックした後の求人票クリック率
- QACサジェストキーワードをクリックした後の求人票応募クリック率
今後の展望
QACシステムを刷新したことでQACのログも落ちるようになり、分析することが可能になったことで、今後、以下のような改善が考えられるようになりました。
- ユーザーからのフィードバックをランキングに組み込む
- ユーザー属性によって表示するQACサジェストキーワードを変更する
- インデックスのデータ量を大きくして、より広範囲のユーザー入力に対してQACサジェストできるようにする
最後に
以上、QACシステムリプレイスの概要をご紹介しました。 今回のリプレイスでは、Elasticsearchなどの単一のソフトウェアを使わずに、AWSの様々なクラウドサービスを組み合わせて検索システムを構築しました。
AWSの様々なクラウドサービスを組み合わせて検索システムを構築することによって、以下4点がこの構成をとったメリットかなと考えています。
- それぞれ処理したいことに特化したサービスを利用でき、さらに何か機能を追加したい時などのカスタム性が高い
- 何か不具合があったときに、それぞれのクラウドサービス上で解決するだけで稼働中のシステムに影響ない
- またどこで何が原因で不具合が発生したのか特定しやすい
- マネージドサービスのため、運用工数が小さい
また個人的には、既存のOSSの検索サーバを利用するのではなくLuceneを直接使うことで、検索エンジンへより深い知識と技術の習得をでき良い経験ができました。
参考文献
スタンバイのプロダクトや組織について詳しく知りたい方は、気軽にご相談ください。 www.wantedly.com