返回所有文章

事件取樣設計:降低位置資料量,為低頻關鍵事件分別設定保留率

每秒回報五次的位置事件,與每次遊玩只回報一次的通關事件,需要不同的取樣策略。如果兩者都只保留 10%,較長的工作階段仍會留下不少位置紀錄,但那一次通關事件通過取樣判斷的機率也只有 10%。

事件取樣依設定的機率保留每個符合條件的事件。先確定資料要回答什麼問題,再為不同事件名稱設定保留率。對於重複的狀態觀測,部分資料可能已經夠用;對於一次失敗或抵達檢查點,每次發生都可能是調查所需的證據。

以下設定針對 Track 事件路徑,已依 Framedash Unity SDK 0.1.8 的實作核對。可選用的逐幀 performance run 擷取使用另一條路徑。文中的事件量是假設計算,不是 Framedash 的實測結果,也不是適合所有遊戲的建議參數。

區分週期性觀測與狀態變化

為每個事件寫清楚呼叫時機與計數含義:

  • player_position:依一定間隔記錄位置,用於觀察大致的移動模式
  • player_death:玩家進入死亡狀態時呼叫一次
  • level_completed:關卡進入完成狀態時呼叫一次

後兩種事件應放在狀態切換的程式碼中。如果生命值為零期間每幀都呼叫 player_death,重複紀錄在取樣前就已產生。降低保留率只會掩蓋其中一部分,無法修正事件定義。

位置回報的呼叫間隔要單獨決定。每秒五次的計時器決定何時嘗試觀測,10% 的保留率再從這些觀測中隨機選擇。經過大量呼叫後,平均每秒保留 0.5 筆位置紀錄。這不等於每兩秒固定保留一筆,也不能保證相鄰紀錄之間的最大時間間隔。

如果要還原一場短暫戰鬥中的精確路線,隨機取樣留下的空白可能太多。應為該問題準備限定時間範圍的詳細紀錄,或明確記錄戰鬥開始與結束事件。提高其他事件的保留率,不會自動補上這些紀錄。

估算自訂事件量

假設一個 20 分鐘的工作階段恰好呼叫 6,000 次位置事件、3 次死亡事件與 1 次通關事件。下表計算的是通過取樣判斷的預期事件數,尚未考慮緩衝、傳輸或資料接收處理的結果。

自訂事件假設呼叫次數全部保留全部保留 10%位置保留 10%,關鍵事件保留 100%
player_position6,0006,000600600
player_death330.33
level_completed110.11
總計6,0046,004600.4604

預期值可以是小數,單次工作階段實際留下的數量則是整數。在獨立隨機取樣模型下,如果這四次關鍵事件各以 0.1 的機率保留,一次都沒有留下的機率就是 0.9^4,約 66%。在這個例子中,讓這四個事件都通過取樣,幾乎不改變整體數量。

表中不含 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,而不是兩者相乘。事件名稱區分大小寫,數值取樣率會被限制在 0 到 1 之間。傳入的值應為該範圍內的有限數值。

全域預設值是 1.0,來自元件中序列化的取樣設定,並在初始化時讀取。事件種類較少時,可以保留這個預設值,只降低明確列出的高頻事件,方便檢查策略。未列出的新事件仍使用預設值,因此新增事件時也要檢查是否意外加入了高頻呼叫。設定與初始化程式碼見 TelemetrySDK.cs。

移除暫時的覆寫值:

sdk.RemoveEventSamplingRate("player_position");

這會恢復為全域保留率,而專案中的全域值不一定是 1.0。覆寫值屬於執行階段狀態,SDK 關閉並重新初始化後需要重新設定。修改只影響此後的取樣判斷,不會改變已在緩衝區中的事件,也無法恢復已捨棄的樣本。

確認哪些 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. 單獨統計場景實際發起的自訂呼叫次數,與後端收到的數量分開
  2. 檢查低頻事件是否只在預期狀態切換時觸發一次,包括重試與重新開始的路徑
  3. 暫時把高頻測試事件的保留率設為 0,再設為 1,核對行為變化;SDK 內部事件不計入這組測試數量
  4. 恢復預定使用的取樣率,重複足夠多次呼叫,觀察數量是否在預期值附近變動,而不要求每個工作階段都恰好達到該百分比
  5. 依照 SDK 的緩衝區送出與診斷說明,單獨檢查緩衝處理與結束時的傳輸

在同一次遙測程式碼審查中,記錄呼叫間隔、各事件保留率以及事件要回答的問題。下一位開發者新增事件時,應能在複製附近的 Track 呼叫之前,判斷這種資料是否允許缺漏。