記事一覧へ戻る

イベントのサンプリング設計:位置情報を間引き、少ない重要イベントを残す

毎秒5回送る位置情報と、1回のプレイで一度だけ送るクリア通知には、別々のサンプリング設定が必要です。 両方の保持率を10%にすると、長いセッションでは位置情報が多く残る一方、クリア通知がサンプリングを通過する確率も10%になります。

イベントのサンプリングは、対象のイベントを指定した確率で残す仕組みです。 まずデータで何を確かめるかを決め、イベント名ごとに保持率を選びます。 繰り返し観測する状態なら一部で足りる場合がありますが、死亡やチェックポイント到達では一度の発生が調査に必要になることがあります。

以下の設定は、Framedash Unity SDK 0.1.8 の実装で確認した Track のイベント記録に関するものです。 任意で使うフレーム単位のperformance run計測は、別の処理を通ります。 件数の例は仮定に基づく試算で、Framedashの実測結果でも、すべてのゲームに勧める設定値でもありません。

繰り返す観測と状態の変化を分ける

イベントごとに、どこで呼び出すか、何を数えるかを書き出します。

  • player_position:移動の大まかな傾向を調べるため、一定間隔で記録する位置
  • player_death:プレイヤーが死亡状態になった瞬間に一度記録する死亡
  • level_completed:レベルがクリア状態になった瞬間に一度記録する完了

後ろの2つは、状態が変わる処理から呼び出します。 体力が0の間、毎フレーム player_death を呼ぶと、サンプリングより前に重複が生じます。 保持率を下げれば重複の一部は消えますが、イベントの定義は直りません。

位置情報の呼び出し間隔は、保持率とは別に決めます。 毎秒5回のタイマーは観測を試みる時刻を決め、10%の保持率はその観測から確率的に選別します。 多数の呼び出しを平均すれば、残る位置情報は毎秒0.5件です。 ただし、2秒に1件ずつ残るわけではなく、観測の途切れる時間にも上限はありません。

短い戦闘中の正確な移動経路を知りたい場合は、ランダムな間引きでは欠落が大きすぎる可能性があります。 その調査に合う期間限定の詳細記録を用意するか、戦闘の開始と終了を明示的なイベントとして残します。 別のイベントの保持率を上げても、これらの記録が自動で追加されることはありません。

カスタムイベントの件数を試算する

20分のセッションで、位置情報を6,000回、死亡を3回、クリアを1回記録すると仮定します。 下の表は、サンプリングを通過する件数の期待値です。 バッファーへの格納、通信、取り込みまでの成否は含みません。

カスタムイベント仮定した呼び出し回数すべて100%すべて10%位置10%、死亡とクリア100%
player_position6,0006,000600600
player_death330.33
level_completed110.11
合計6,0046,004600.4604

期待値には小数が出ますが、1回のセッションで残る件数は整数です。 4件の死亡とクリアをそれぞれ独立に確率0.1で残すと仮定すると、1件も残らない確率は 0.9^4、約 66% です。 この例では、4件をサンプリングで落とさない設定にしても、全体の件数はほとんど変わりません。

表には、SDKが内部で生成するイベントや、ほかの計測処理を含めていません。 料金や配信済み件数の試算にも使えません。 実際の量には、ペイロードの大きさ、セッションの長さ、ほかのイベント、配信の成否も関係します。

初期化後にイベント別の保持率を設定する

SDKの初期化が成功した後、ゲームプレイの開始前に設定します。

using Framedash;

// Run after the project's TelemetrySDK.Initialize(...) call.
var sdk = TelemetrySDK.Instance;
sdk.SetEventSamplingRate("player_position", 0.10f);
sdk.SetEventSamplingRate("player_death", 1.0f);
sdk.SetEventSamplingRate("level_completed", 1.0f);
sdk.SetEventSamplingRate("map_load", 1.0f);

イベント名は、ゲームが実際に使う名前と一致させます。 この例の player_position、player_death、level_completed は、ゲーム側で定義する名前です。 保持率を設定しても、SDKがこれらのイベントを生成するようにはなりません。 map_load は、SDKのマップロード報告用メソッドから生成されます。

イベント別の設定はUnity SDKガイドに記載されています。 0.1.8のサンプリング実装では、イベント別の値がグローバルな値を置き換えます。 グローバルが0.1でイベント別が1.0なら、そのイベントには1.0を使い、2つの値を掛け合わせません。 名前の大文字と小文字は区別され、数値の保持率は0から1にクランプされます。 有限の0から1の値を渡してください。

グローバルな保持率の既定値は1.0で、コンポーネントのシリアライズされた設定を初期化時に読み込みます。 イベントの種類が少なければ、この既定値を保ち、頻度の高いイベントだけを指定して下げると、設定を確認しやすくなります。 未登録の新しいイベントには既定値が使われるため、高頻度の呼び出しを誤って追加していないかもレビューします。 設定と初期化はTelemetrySDK.csで確認できます。

一時的な設定を外す場合は、次を呼びます。

sdk.RemoveEventSamplingRate("player_position");

戻る先はグローバルな保持率で、プロジェクトによっては1.0とは限りません。 イベント別の設定は実行時の状態なので、SDKをシャットダウンして再初期化した場合は設定し直します。 変更が効くのは以後のサンプリング判定で、バッファー内のイベントや、すでに間引いたイベントにはさかのぼりません。

サンプリングを通らないSDKイベントを確認する

位置情報と死亡やクリアのカスタムイベントはイベント別のサンプリングを通り、内部のセッション開始とheartbeatは迂回する。どちらも、その後にバッファーと配信処理を通る。

イベント記録の実装では、次のように扱いが分かれます。

  • SDK内部の session_start と perf_heartbeat は、イベントのサンプリングを通らない
  • カスタムの Track(...) 呼び出しは、イベント別の保持率を使い、指定がなければグローバルな保持率を使う
  • EndMapLoad() や ReportMapLoad(...) が生成する map_load は Track(...) を通るため、サンプリングの対象になる

ここで「自動」と呼ぶのは、SDK内部から記録する処理です。 BeginAutomatedSession(...) はセッションのメタデータを付けますが、カスタムイベントをサンプリング対象外にはしません。 内部イベントと同じ名前をカスタムの Track に渡しても、内部用の処理には切り替わりません。

保持率1.0は、有効な呼び出しをサンプリング判定で落とさない設定です。 配信の保証ではありません。 初期化、入力の検証、バッファー容量、終了処理、通信や取り込みの失敗は別に確認する必要があります。 これは、サンプリングを通らないSDKイベントも同じです。

サンプリングで省けるのは、判定より後の処理です。 このSDKの Track は、属性をシリアライズ用に整えたり、イベントの性能値を収集したりする前に保持率を判定します。 一方、ゲーム側で Track を呼ぶ前に行った辞書の確保や計算は、すでに終わっています。 その処理が重ければ、保持率とあわせて呼び出し間隔やペイロードの準備も見直します。

間引いた件数から何を計算できるか

サンプリング後の件数は、残った観測の数です。 既知の一定の保持率0.1で600件残ったなら、ランダムサンプリングを仮定し、ほかに欠落がなければ、600 / 0.1 から元の呼び出し回数を6,000回と推定できます。 失われた時刻や位置、セッション内の履歴までは復元できません。

保持率は、ビルドやテストの設定と一緒に記録します。 実行の途中で変えるなら、変更前後を分けて集計できる情報を自分たちの計測記録に残します。 不明な比率で混ざった保持率を、単一の係数では補正できません。 既存のダッシュボードが保持率の逆数による重み付けを自動で行うとも仮定しないでください。

割合を求めるには、イベントの定義と母集団をそろえます。 挑戦回数に対するクリア率なら、挑戦開始とクリアの定義を一緒に決め、量が許せば両方を間引かずに残します。 間引かないクリア件数を、間引いた位置情報の件数で割っても、クリア率にはなりません。 両方が1.0でも、呼び出しの重複や未配信を確かめたうえで解釈します。

イベント単位の間引きでは、順序の一部も抜けます。 クリアだけが残り、開始が残っていなくても、プレイヤーが開始を飛ばした根拠にはなりません。 少ないサンプルから完全なファネルや1人の移動経路を組み立てる用途は避けます。

呼び出し回数がわかるシナリオで試す

設定を広く使う前に、開発用の実行で次を確かめます。

  1. シナリオが呼んだカスタムイベントの件数を、バックエンドに届いた件数とは別に数える
  2. リトライや再開も含め、少ないイベントが意図した状態変化で一度だけ発生するか確認する
  3. 頻度の高いテスト用イベントの保持率を一時的に0、次に1にして変化を確かめる。SDK内部のイベントは、この件数から分ける
  4. 本来の保持率に戻し、十分な回数を試す。セッションごとに同じ割合になることは求めず、期待値の周囲で変動するか見る
  5. バッファーと終了時の配信は、SDKのフラッシュと診断の手順に沿って別に確認する

呼び出し間隔、イベント別の保持率、そのイベントで答えたい問いを、同じ計測レビューに残します。 次にイベントを追加する開発者が、近くの Track 呼び出しをコピーする前に、欠落を許容できるか判断できる形にしておきます。