查詢巢狀JSON
Telemetry 將巢狀的 JSON 物件轉換為可查詢的點狀欄位路徑。這樣可以在攝取時將相關上下文保持在一起,同時仍然使各個值可供 SQL 使用。
本指南涵蓋了從事件契約到過濾器、聚合、架構更改和故障排除的完整路徑。在複製查詢之前檢查表架構:確切的識別符號拼寫和型別來自您傳送的事件。
設計一個穩定的巢狀事件
當欄位形成一個持久概念時,請使用巢狀物件。保持值的型別,省略敏感的有效負載,並避免將頻繁更改的結構放入陣列中。
{
"event_name": "tool_call_completed",
"event_id": "evt_7f31",
"account_id": "acct_8f31",
"release": "2026.07.3",
"workflow": {
"name": "answer_question",
"version": "v2"
},
"tool": {
"name": "inventory_lookup",
"outcome": "success",
"duration_ms": 184,
"usage": {
"input_units": 820,
"output_units": 244
}
}
}
行粒度是一次完成的工具呼叫。 tool.duration_ms 始終是數字,tool.outcome 來自受控集,並且識別符號是假名的。請求參數、模型提示、生成的內容、憑據和原始錯誤訊息故意不存在。
透過SDK傳送物件:
await telemetry.log("tool_call_completed", event);
日誌 API 新增查詢中使用的託管事件時間,並遞迴刪除空值、空物件和空陣列。在使用空值作為業務狀態之前,請先閱讀 事件資料型別與可空性。
聚合前檢查
從有界樣本開始。根據資料表模式,巢狀路徑可以顯示為複合識別符號或需要一個雙引號點識別符號:
SELECT
timestamp_utc,
event_id,
workflow.name,
tool.name,
tool.outcome,
tool.duration_ms
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '1 hour'
ORDER BY timestamp_utc DESC
LIMIT 50;
如果架構公開了文字點分列名稱,請引用完整路徑:
SELECT
"workflow.name",
"tool.name",
"tool.duration_ms"
FROM tool_call_completed
LIMIT 50;
不要透過猜測在帶引號和不帶引號的形式之間切換。檢查表架構,執行一個小樣本,並使用與儲存欄位匹配的表單。
過濾和聚合巢狀欄位
巢狀欄位適用於過濾器、組、計算和排序。此查詢在完整的有界視窗上比較工具數量、故障和 p95 持續時間:
SELECT
tool.name AS tool_name,
COUNT(*) AS calls,
SUM(CASE WHEN tool.outcome = 'error' THEN 1 ELSE 0 END) AS errors,
100.0 * SUM(CASE WHEN tool.outcome = 'error' THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS error_rate_pct,
approx_percentile_cont(tool.duration_ms, 0.95) AS p95_duration_ms
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
AND workflow.name = 'answer_question'
GROUP BY tool.name
HAVING COUNT(*) >= 20
ORDER BY error_rate_pct DESC, calls DESC;
如果您的資料表使用帶引號的點識別符號,請在同一查詢中引用每個完整路徑:
SELECT
"tool.name" AS tool_name,
approx_percentile_cont("tool.duration_ms", 0.95) AS p95_duration_ms
FROM tool_call_completed
WHERE "workflow.name" = 'answer_question'
GROUP BY "tool.name";
故意處理缺失的路徑
在引入 tool.usage.output_units 之前建立的舊行將沒有該欄位。具有 null、空物件或空陣列值的新事件在規範化後也不會儲存該路徑的值。
在依賴新欄位之前使用 IS NULL 測量覆蓋範圍:
SELECT
release,
COUNT(*) AS calls,
SUM(CASE WHEN tool.usage.output_units IS NULL THEN 1 ELSE 0 END)
AS missing_output_units,
100.0 * SUM(CASE WHEN tool.usage.output_units IS NULL THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS missing_rate_pct
FROM tool_call_completed
WHERE timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY release
ORDER BY release;
請勿用零替換缺失的數字,除非零是正確的業務含義。 “未報告”、“不適用”和實際測量為零是不同的狀態。
安全地演化巢狀路徑
將每個點路徑視為模式契約:
| 改變 | 效果 | 更安全的推出 |
|---|---|---|
新增tool.usage.cache_hit |
現有行沒有值 | 新增鍵入的欄位,測量覆蓋範圍,然後更新消費者 |
重新命名tool.name |
現有查詢仍然讀取舊路徑 | 遷移時雙寫新舊路徑 |
將 tool.duration_ms 從數字更改為字串 |
型別衝突可能會拒絕攝取 | 新增新的數字欄位並遷移 |
將 tool.outcome 移動到另一個物件 |
建立新路徑,而不是原地移動 | 對合約進行版本控制並暫時支援這兩種路徑 |
| 更改陣列元素形狀 | 產生不穩定的分析契約 | 每個持久結果發出一行或使用固定命名欄位 |
在每個深度都保持相同的含義和型別。新增可選的巢狀欄位通常是相容的;改變路徑的型別或重新使用它以獲得新的含義則不是。
決定何時展平
巢狀物件對於穩定的名稱空間非常有用,例如 tool、workflow 或 billing。當平面欄位用於幾乎每個查詢或儀表板時,它會更好。
在以下情況下更喜歡平坦或單獨發射的場:
- 該值定義了行粒度或主要事件結果;
- 操作員幾乎在每次調查中都必須對其進行掃描;
- 多個生產者無法就一種巢狀結構達成一致;
- 陣列實際上代表了多個獨立的結果。
稍後從巢狀更改為平面是架構遷移。根據問題和所有權邊界進行選擇,而不是根據有效負載的美觀進行選擇。
解決巢狀欄位查詢問題
如果查詢找不到巢狀路徑:
- 使用
LIMIT 50查詢最近的原始樣本。 - 檢查表架構中是否有準確的點名稱和型別。
- 嘗試模式的帶引號的識別符號形式,而不是新增來自另一種 SQL 方言的 JSON 提取語法。
- 確認生產者確實傳送了一個非空、非空值。
- 按
release或生產者版本對缺失值進行分組。 - 檢查新舊生產者之間的型別變化。
- 在恢復連線或聚合之前,將查詢減少到一個欄位和一個最近的時間視窗。
Telemetry 使用 DataFusion SQL,因此從其他系統複製的 PostgreSQL、BigQuery、Snowflake 或 MySQL JSON 函式可能不適用。使用 DataFusion SQL 參考 中練習的語法。
生產清單
- 賦予每個巢狀物件一個持久的意義和所有者。
- 保持每條路徑的型別、單位和控制值穩定。
- 排除機密、使用者內容、原始負載和無限制的錯誤文字。
- 測試成功、失敗、缺場和舊版本裝置。
- 在儀表板或警示依賴新領域之前先衡量新領域的採用情況。
- 記錄行粒度、保留需求和遷移計劃。