RobloxがTheta Sketchesを活用してクリエイター分析機能を拡張した方法

今日のリアルタイムマルチプレイヤーゲームにおいて、アナリティクスは不可欠です。Robloxでは、クリエイターが活躍できるよう、測定ツールの開発に注力しています。当社の無料ですぐに使えるアナリティクス機能により、クリエイターは自身の体験コンテンツの成長、ユーザー獲得、および定着率に関するインサイトを即座に把握でき、成功を最大化することができます。
数百万人のRobloxクリエイターが依存する最新の分析システムを構築することは、重要な課題です。この課題に取り組むため、当社は分析クエリエンジンを最適化し、120コアの処理クラスターが、86TBのデータにアクセスする約30万人の日次訪問者から、1日あたり600万件以上のクエリに対応できるようにしました。 当社のソリューションの中核をなすのは、スケーラビリティと近似アルゴリズムとの統合性を理由に採用したオンライン分析処理(OLAP)データベースです。データ集計手法に加え、HyperLogLogおよびTheta Sketchアルゴリズムを組み合わせて活用することで、数百万ものRobloxエクスペリエンス1に対する分析機能を提供しています。
OLAP分析入門
クエリの対象となるデータ量が多ければ多いほど、結果の生成には時間がかかります。必要なデータ量を削減し、分析プロセスを高速化できれば、クリエイターは自身のアクションからほぼリアルタイムのインサイトを得ることができます。当社が活用している手法には、以下のようなものがあります:
- 列指向ストレージ:OLAPであるDruidは、必要な列のみを読み込みます。
- パーティションおよびソートフィルター:OLAPは、必要なデータブロックに直接インデックスが張られた関連ファイルのみを読み込みます。
- ロールアップ:OLAPは共通のグループ化を使用してイベントを部分的に集計します。
特にロールアップにより、OLAPはSparkやPrestoのような最大規模のSQLクエリエンジン(数十秒のレイテンシ)と、通常は完全に集計されたデータを提供するポイントクエリや限定的なSQLとの間で動作できるようになります。ロールアップにより、クエリはディメンションのグループ化によってキー付けされるため、総行数が大幅に削減されます。 数十億、あるいは数兆件もの生イベントを扱う場合、それらを数百万のグループにロールアップし、1秒未満のレイテンシで集計を行う方がはるかに効率的です。例えば:

ロールアップには前述のような削減の利点がありますが、一意カウント、パーセンタイル、頻度クエリなど、生データの全テーブルソートを必要とするクエリを含む特定のメトリクスについては、ロールアップが適用しにくい場合があります。
幸いなことに、データセット全体のサンプルを保持する複雑なデータ構造に基づき、統計的に許容範囲内の近似結果を返す技術を用いることで、これらの制限を回避できます。これらのデータ構造はロールアップ技術での使用を想定して設計されており、2つの異なるカウントを、2つの数値を足し合わせるように、結合(union)演算によって統合します。
Robloxアナリティクスのワークロードを分析する
Robloxでは、クリエイターが最も重要なインサイトを確認できる一元化されたダッシュボードを提供しています。これには以下が含まれます:
- エンゲージメント:1日あたりアクティブユーザー(DAU)、1ヶ月あたりアクティブユーザー(MAU)、継続率、およびファネル
- 収益化:収益、ユーザー1人あたりの平均収益、売上、およびエコノミー
- ユーザー獲得データ
- サムネイルのパーソナライゼーションと実験結果
- ホームページのレコメンデーション分析
- その他、今後追加予定。

クエリエンジンの選択と最適化
パフォーマンス上の課題の克服
本番環境での最終段階のシャドーテストにおいて、重要な課題が判明しました。単一の大型クエリから日次集計パターンへの切り替え後、MAUクエリのパフォーマンスを強化する必要があったのです。これらは、クリエイター分析の可視化において極めて重要です。
クエリの構造が、OLAPソリューションの基盤となるパフォーマンスに多大な影響を与えることが判明しました。複数の実行段階を持つ標準的なクエリ(ネストされた「GROUP BY」ステートメントなど)は、処理の大部分を軽量なブローカーノードに押し付けてしまうことがよくあります。
これは、クエリの一部が重要な小型のサービングノード上で実行されてしまうという、典型的なビッグデータの問題です。我々は、近似データ構造が単純なカウントや合計のように機能すると予想していましたが、実際には全く異なる挙動を示していることが判明しました。
下の図はこの問題を示しています。これは、履歴ノードが部分集計を行い、毎日ごとにTheta Sketchをロールアップして、そのデータをブローカーにプッシュする様子を示しています。その後、ブローカーは、各日ごとの大きなスケッチを、1日あたりの単一の月次値にマージしようと試みました。 30日分のMAU(月間アクティブユーザー数)の場合、これはブローカー上で最大サイズのTheta Sketch 1,800個をマージすることを意味し、その結果、クエリの処理が遅くなり、障害が発生しやすくなるだけでなく、ブローカーのCPUを独占する事態を招いていました。

私たちの解決策は、近似クエリに依存するデータソースのデータ局所性を最大化するため、大規模な履歴ワーカーの数を減らしてOLAPを実行することでした。実際、これにより、100MB以上のデータ処理を必要とした可能性のあるマージ操作が、履歴ノード側に戻されることになりました。
SQLでこれを実現するため、インライン結合を使用してクエリが必要な情報を履歴ノードに伝播させ、インライン結果日付のリストを含むクエリを準備しました。各結果日付は、履歴ノードセグメントから関連データを収集できます。その後、データはブローカーに返され、以下に示すように、結果が結果日付とメトリックデータの単一マップに迅速にマージされます。

この最適化は、大規模なクエリのパフォーマンスに劇的な効果をもたらしました。主要なサービスの国別MAU内訳に関するクエリでは、下図に示すように、平均クエリ処理時間が5倍改善されました(17.53秒から3.23秒へ)。また、ブローカー側のCPU処理時間も50分の1に短縮されました(16.83秒から0.34秒へ)。
結果はケースによって異なりますが、これは(数百万のスケッチをマージするといった)複雑な操作を慎重に扱うことの重要性を浮き彫りにしています。こうした操作を単純な集計と同等であると見なすと、特にラストマイルのクライアント側集計が一般的であるシステムにおいて、重大なパフォーマンス問題を引き起こす可能性があります。
ロールアップと理論的シータ・キューブ

また、近似集合交差を用いて、基本的なロールアップテーブルと完全な生データテーブルの間のギャップを埋める一般化されたアプローチである「シータ・キューブ」についても検討しました。このアプローチは、クエリが多数の階層にわたる高カーディナリティのディメンションにアクセスする必要がある場合、ロールアップテーブルの利点が失われるという根本的な制限に対処するものです。これは、各ディメンションによってロールアップのカーディナリティが ∏dim(ディメンションの積)としてスケールしてしまうためです。
そこで我々は、カーディナリティの上限を設けた共通のディメンショングループごとに集計を行い、グループ内のあらゆる対象に対してロールアップクエリのパフォーマンスを確保できるシステムを設計した。その後、グループを跨ぐディメンションの組み合わせを検索する際には、集合間の近似的なjoin4を試行し、メトリクスの結果と共に誤差の推定値を返すようにした。推定誤差が大きいクエリは生テーブルに転送され、そこでは多数のフィルタによって大規模なプッシュダウン最適化が可能となるはずである。


このエラー率を迅速に計算できるため、これは生テーブルの読み取りがパフォーマンス面で有利である可能性が高いという強力なシグナルともなります。重複データがユニオンに対して小さい場合(例えば、ドイツ在住の日本語話者など)、生テーブルの行の多くがフィルタリングされます。その結果、効率的なプッシュダウン最適化が実現されます。 ディメンショングループ、近似結合、およびエラーベースの生テーブル読み取りを利用するシステムは、近似処理に適したクエリにおいてロールアップのパフォーマンスを真に最大化します。
Roblox にとって、このソリューションは次のスケール段階(ダイナミックファネルやカスタムイベント分析など)でより適用可能となるでしょう。一方、現在のシンプルなロールアップレプリカは、現時点のニーズを満たしています。
セルフサービスプラットフォームの構築
ブローカーの最適化が完了した後、私たちはOLAPソリューションに追加されたデータセットのオンボーディングおよびクエリ実行のためのツール構築に注力しました。データスケッチ関数向けにオープンソースのSparkおよびTrino UDAFライブラリを構築し、SparkがOLAP6と同じバイナリデータスケッチ形式を使用できるようにしました。これにより、計算ワークロードの大部分をSpark内に維持し、Roblox全体での近似処理の標準化を実現しました。その結果、特定のデータセットにおいて計算コストを最大80%削減できる可能性があります。
バッチジョブスケジューラの内部拡張機能によりオンボーディングを簡素化し、開発者が確定的なメトリクスとディメンションを決定できるよう導くDataFrameスタイルのAPIを定義することで、オープンクエリの影響を軽減しました。また、OLAPでのデータ読み込みおよびクエリの実行方法に関するサンプルワークフローの一部をオープンソース化しました。
最適化された分析データセットは、現在クリエイターに深い洞察を提供しています。これらの最適化により、平均パフォーマンスは4倍、ワーストケースのパフォーマンスは50倍向上しました。セルフサービス型プラットフォームにより、クリエイターアナリティクスチームは開発者向けの新しいデータセットを継続的に改善することができます。あらゆる規模の開発者がこれらのツールを活用し、Roblox上で素晴らしい体験を創り出していくことを楽しみにしています。
1 過去60日間にアクセス
があったユニークなユニバース数に基づいて算出 2 このような単純なMAUクエリと同様
3 結果は2025
年3月21日~28日のもの 4 以下の方法で実行:SELECT c.experience_id, c.country, p.platform, THETA_INTERSECT(c.user_theta, p.user_theta) from (select experience_id, country, user_theta from theta_cube where agg_level = country) c union (select experience_id, platform, user_theta from theta_cube where agg_level = platform) p
5 https://datasketches.apache.org/docs/Theta/ThetaSketchSetOpsAccuracy.html
6 DruidのSQL関数を通じて COMPLEX_DECODE_BASE64('HLLSketch', sketch_col_name ).


