查询
查询 API 允许您针对 Telemetry 数据运行 SQL。
发布 https://api.telemetry.sh/query
标题
| 名称 | 类型 | 描述 |
|---|---|---|
| 内容类型 | 字符串 | 应用程序/json |
| 授权 | 字符串 | 您的 API 密钥,作为原始密钥或 Bearer <key> |
身体
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| 查询 | 字符串 | 是的 | 要执行的 SQL 查询。 |
| 实时 | 布尔值 | 否 | 默认为 true。传递到查询服务。 |
| json | 布尔值 | 否 | 默认为 true。传递到查询服务。 |
成功响应,200 OK
{
"status": "success",
"data": [
{
"city": "paris",
"average_price": 42.0
}
],
"key_order": ["city", "average_price"]
}
data 包含结果行。 key_order 保留查询结果中的列顺序。
cURL 的使用示例
此 cURL 请求查询 uber_rides 中各城市的平均车费:
QUERY=$(cat <<'SQL'
SELECT
city,
AVG(price) AS average_price
FROM
uber_rides
GROUP BY
city
LIMIT
10000;
SQL
)
curl -X POST https://api.telemetry.sh/query \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d "$(jq -n --arg query "$QUERY" '{query: $query, realtime: true, json: true}')"
使用 JavaScript SDK
我们建议使用 SDK 以获得更好的开发人员体验:
import telemetry from "telemetry-sh";
telemetry.init("YOUR_API_KEY");
const results =
await telemetry.query(`
SELECT
city,
AVG(price)
FROM
uber_rides
GROUP BY
city
`);
异步查询
较小的 JSON 结果通过 result 中的 data 和 key_order 直接返回。较大的 JSON 结果和 Parquet 导出使用 download_url。完成响应只需提供其中一种;直接返回的结果不需要下载 URL 或 URL 过期字段。如果 download_url_expired 为 true,请发起新查询。过期字段是可选的。
这对于导出整个表、运行大量聚合或将结果下载为 JSON 或 Parquet 文件特别有用。
它是如何运作的
- 开始 —
POST您对/query/async的查询。服务器返回job_id和status_url。 - 轮询 —
GETstatus_url以检查进度。 - 读取
result中的结果,或从download_url下载文件。
API 参考
启动异步查询
发布 https://api.telemetry.sh/query/async
标题
| 名称 | 类型 | 描述 |
|---|---|---|
| 内容类型 | 字符串 | 应用程序/json |
| 授权 | 字符串 | 您的 API 密钥,作为原始密钥或 Bearer <key> |
身体
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| 查询 | 字符串 | 是的 | 要执行的 SQL 查询。 |
| 实时 | 布尔值 | 否 | 默认为 true。传递到查询服务。 |
| json | 布尔值 | 否 | 默认为 true。传递到查询服务。 |
| 格式 | 字符串 | 否 | 结果格式:"json"(默认)或"parquet"。 |
回复(已接受 202)
{
"status": "accepted",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"format": "json",
"status_url": "/query/async/550e8400-e29b-41d4-a716-446655440000"
}
投票查询状态
获取 https://api.telemetry.sh/query/async/{job_id}
标题
| 名称 | 类型 | 描述 |
|---|---|---|
| 授权 | 字符串 | 您的 API 密钥,作为原始密钥或 Bearer <key> |
响应(200 OK)
直接返回的 JSON 结果
{
"status": "success",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"query_status": "completed",
"format": "json",
"progress_pct": 100,
"result": {
"data": [{ "events": 7 }],
"key_order": ["events"]
}
}
可下载的结果
{
"status": "success",
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"query_status": "completed",
"format": "json",
"progress_pct": 100,
"message": "Query completed",
"created_at": "2025-02-24T12:00:00Z",
"completed_at": "2025-02-24T12:00:05Z",
"download_url": "https://storage.example.com/results/...",
"download_url_expires_in_seconds": 3600
}
当 format 为 "json" 时,下载的文件包含查询元数据以及 result 下的标准查询结果形状:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"format": "json",
"result": {
"data": [
{
"city": "paris",
"average_price": 42.0
}
],
"key_order": ["city", "average_price"]
}
}
query_status 字段将是以下之一:
| 状态 | 描述 |
|---|---|
queued |
查询正在等待执行 |
running |
查询当前正在执行 |
completed |
结果通过 result 或 download_url 提供。 |
failed |
查询失败。检查 error 字段。 |
cancelled |
查询已取消。 |
使用 cURL 进行异步查询
# 1. Start the async query
QUERY='SELECT * FROM uber_rides'
RESPONSE=$(curl --fail-with-body -sS --max-time 30 https://api.telemetry.sh/query/async \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d "$(jq -n --arg query "$QUERY" '{query: $query, format: "json", realtime: true, json: true}')") || exit 1
STATUS_URL="https://api.telemetry.sh$(echo "$RESPONSE" | jq -r '.status_url')"
# 2. Poll for at most ten minutes
DEADLINE=$((SECONDS + 600))
while [ "$SECONDS" -lt "$DEADLINE" ]; do
STATUS=$(curl --fail-with-body -sS --max-time 30 -H "Authorization: $API_KEY" "$STATUS_URL") || exit 1
QUERY_STATUS=$(echo "$STATUS" | jq -r '.query_status')
if [ "$QUERY_STATUS" = "completed" ]; then
if echo "$STATUS" | jq -e '.download_url_expired == true' >/dev/null; then
echo "Result expired. Start a new query."
exit 1
elif echo "$STATUS" | jq -e '.result | type == "object"' >/dev/null; then
echo "$STATUS" | jq '{result: .result}' > results.json
else
DOWNLOAD_URL=$(echo "$STATUS" | jq -r '.download_url // empty')
if [ -z "$DOWNLOAD_URL" ]; then
echo "Completed response has neither a result nor an active download URL."
exit 1
fi
curl --fail-with-body -sS --max-time 300 -o results.json "$DOWNLOAD_URL" || exit 1
fi
# Both branches have the same result shape, including an empty data array.
jq '.result' results.json
exit 0
elif [ "$QUERY_STATUS" = "failed" ] || [ "$QUERY_STATUS" = "cancelled" ]; then
echo "Query $QUERY_STATUS: $(echo "$STATUS" | jq -r '.error // .message')"
exit 1
elif [ "$QUERY_STATUS" != "queued" ] && [ "$QUERY_STATUS" != "running" ]; then
echo "Unexpected query status: $QUERY_STATUS"
exit 1
fi
sleep 5
done
echo "Query polling timed out."
exit 1
示例:导出整个表
异步查询 API 非常适合全表导出。由于异步查询没有行数限制,因此您可以导出所有内容并将结果下载为单个文件。
# Start the export as Parquet
QUERY='SELECT * FROM uber_rides'
RESPONSE=$(curl -s -X POST https://api.telemetry.sh/query/async \
-H "Content-Type: application/json" \
-H "Authorization: $API_KEY" \
-d "$(jq -n --arg query "$QUERY" '{query: $query, format: "parquet", realtime: true, json: true}')")
STATUS_URL="https://api.telemetry.sh$(echo "$RESPONSE" | jq -r '.status_url')"
# Poll until complete
while true; do
STATUS=$(curl -s -H "Authorization: $API_KEY" "$STATUS_URL")
QUERY_STATUS=$(echo "$STATUS" | jq -r '.query_status')
if [ "$QUERY_STATUS" = "completed" ]; then
DOWNLOAD_URL=$(echo "$STATUS" | jq -r '.download_url // empty')
if [ -z "$DOWNLOAD_URL" ]; then
echo "Export completed, but no active download URL is available."
exit 1
fi
curl -o uber_rides_export.parquet "$DOWNLOAD_URL"
echo "Export complete: uber_rides_export.parquet"
break
elif [ "$QUERY_STATUS" = "failed" ]; then
echo "Export failed: $(echo "$STATUS" | jq -r '.error // .message')"
exit 1
fi
sleep 5
done
SDK边界
当前JavaScript SDK的query方法调用交互式/query
端点。它不会启动 /query/async、轮询 status_url、强制执行
异步作业超时,或下载完成的工件。
对于大型 JSON 或 Parquet,使用上面的 HTTP 启动、轮询和下载流程
出口。应用程序包装器可以封装这三个操作,但它
仍应执行总投票截止日期,停止 failed,并处理
过期的 download_url 作为新导出而不是重试旧下载
无限期地。
常见错误
400 Bad Request如果 JSON 主体无效400 Bad Request如果query缺失或为空401 Unauthorized(如果 API 密钥丢失或无效)402 Payment Required(如果帐户被付费墙支票封锁)429 Too Many Requests如果 API 密钥超过网关速率限制