ご想像のとおり、PayPayは多くの情報やデータを扱っていますが、プライバシーの観点から、サイロ化された安全な状態でそれらを保管しています。しかし、優れたユーザー体験を提供するためには、好きな商品、店舗、サービスをアプリでユーザーが簡単に検索できるようにしなくてはなりません。また、より良いお客様へのサポートを提供し、より効果的な製品を開発し、ユーザーが必要な情報を確実に入手できるように、PayPayは組織として、ユーザーや加盟店データベースのデータや分析にアクセスしなくてはなりません。データを適切なタイミングで適切に扱いやすい形で提供することは、PayPayのサービスの重要なバックボーンとなっているのです。

この情報の提供が遅れると、ユーザーと加盟店の双方にマイナスの体験となる可能性があります。遅延は、多くのデータベースやテーブルにまたがる検索データと、情報の取得やソートにかかる時間によって発生します。この問題を解決し、ユーザーにとって効率的であるために、Elasticsearchを使用しています。 

Elasticsearchは、テキスト、数値、地理空間、構造化、非構造化など、あらゆる種類のデータを対象とした分散型オープンソースの検索・分析エンジンです。 シンプルなRESTベースのAPI、分散性、スピード、スケーラビリティで知られるElasticsearchは、Elastic Stackの中心的なコンポーネントです。  

Elasticsearchの活用場面

  • 全文検索に適している
  • ビッグデータに適している(トランザクションクエリなし)
  • ファセット検索 (フィルタリング)
  • 地理的クエリー

アーキテクチャとデータ構造

ElasticsearchはすべてのデータをJSON形式で保存し、curl、ウェブブラウザ、REST API、または任意の標準的なlibを使用してHTTPでアクセスすることができます。

Elasticsearchは、これらのJSONデータを格納することができる概念上のバッグを持っています。これらのバッグはインデックスと呼ばれ、リレーショナルデータベースモデルのデータベースに似ています。各インデックスの内部には、リレーショナル・モデルのテーブルに似た複数のDOCTYPEが格納されます。DOCTYPEのスキーマは常に明示的に指定することが推奨されています。複数のドキュメントは、テーブルの行のように1つのDOCTYPE内に格納することができます。

ESは実際どのように検索しているのか?

ESでは、転置インデックスを使用して、クエリや検索の結果を提供します。転置インデックスは、基本的には各単語とdoc_idとの対応関係を格納したテーブルです。

上の図では、doc 0,1,2にはrowの単語が、doc 1,2にはboatが、doc 2にはchickenが表示されています。転置インデックスマッピングを利用して、UNIONとINTERSECTIONが簡単に適用でき、単語の組み合わせに関連するdocを見つけることができます。しかし、上記のマッピングでは、doc内の単語の位置情報が含まれていないので、「row boat」のような全文検索には役立ちません。

Elasticsearch内の全文検索はどのようにして実行されるのか?

全文検索を行うために、ESは単語の位置を doc_id と一緒に転置インデックスマッピングテーブルに格納します。

単語の位置を利用し、下図のような簡単な操作をすることで、関連する文書を見つけることができます。

“row boat”を検索するには、両方の単語を含むドキュメントだけをフィルタリングすることができます。フィルタリング後、適切なロジックが1つずつ適用され、単語「row」の直後の位置に「boat」を含むドキュメントを検索します。

クエリかフィルタリングかを判断するには?

Elasticsearchはクエリとフィルタリングの両方に対応しています。フィルタリングの方が速く、キャッシュ可能で、ブーリアンの結果を返します。逆に、クエリは遅く、キャッシュ不可能で、ファジースコアを返します。単純な経験則で言えば、クエリは必須の場合にのみ実行するべきです。

PayPayでのElasticsearch

PayPayのMerchant Teamでは、加盟店登録の申請情報の検索にフィルタリング方式を採用していました。その理由としては、検索クエリには常に特定のIDやフィールド名が多数含まれており、ファジークエリはこのシナリオでは無意味で時間がかかるからです。 

また、PayPayピックアップサービスの店舗・メニュー検索機能にもESを使用し、日本語クエリに特化した正確な検索結果を開発、最適化しました。