大规模 Quantified Self:使用 ClickHouse 处理数百万可穿戴指标 🚀
I’m happy to translate the article for you, but I need the full text of the post. Could you please paste the content you’d like translated (excluding the source line you’ve already provided)? Once I have the article text, I’ll translate it into Simplified Chinese while preserving the original formatting, markdown syntax, and technical terms.
介绍
你是那种会追踪每一次心跳、步数和睡眠阶段的数据狂热者吗?如果你拥有 Oura Ring 和 Apple Watch,那么你手中就掌握着一座高频生物特征数据的金矿。随着你的 Quantified Self 之旅不断深入,简单的 CSV 或标准关系型数据库很快就会变得捉襟见肘。当你需要处理数百万条传感器读数时,你就需要一台速度之王。
在本指南中,我们将深入探讨个人健康的数据工程,阐明为何 ClickHouse 是时间序列健康数据的终极选择,以及如何构建一个能够在亚秒级提供洞察的管道。我们将覆盖高性能列式存储、针对时间序列分析的高效模式设计,以及实时可视化。
数据摄取管道
graph TD
A[Oura Ring API] -->|JSON| B(Python Ingestion Engine)
C[Apple Watch Export] -->|XML/CSV| B
B -->|Pandas/Batch| D{ClickHouse DB}
D -->|SQL Aggregation| E[Apache Superset]
D -->|Analysis| F[Jupyter Notebooks]
style D fill:#f96,stroke:#333,stroke-width:4px
为什么选择 ClickHouse 进行可穿戴设备指标分析
当你拥有数百万行心率数据(每几分钟甚至每秒采样一次)时,传统数据库如 PostgreSQL 在分析聚合时会捉襟见肘。ClickHouse 的优势在于:
- 列式存储 – 只读取你需要的列(例如仅
heart_rate)。 - 数据压缩 – 1000 万行数据可以压缩到原始大小的很小一部分。
- 向量化执行 – 以块的方式处理数据,使得诸如“每月平均心率”之类的查询几乎是瞬时完成的。
架构设计
在高性能的部署中,架构设计至关重要。我们将使用 MergeTree 引擎,它是 ClickHouse 的主力引擎。
CREATE TABLE IF NOT EXISTS health_metrics (
event_time DateTime64(3, 'UTC'),
metric_name LowCardinality(String),
value Float64,
source_device LowCardinality(String),
user_id UInt32,
-- Tags for extra metadata (e.g., 'sleep', 'workout')
tags Array(String)
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_time)
ORDER BY (user_id, metric_name, event_time)
SETTINGS index_granularity = 8192;
为什么这样有效
LowCardinality(String):为重复出现的值(如metric_name的 “HeartRate”、 “SPO2”)节省空间。PARTITION BY:加速删除操作,并按月份组织数据。ORDER BY:决定磁盘上的物理排序,使 ClickHouse 能够极快定位特定用户的特定指标。
使用 Python 进行摄取
我们使用 clickhouse-connect 库来提供高性能的接口。我们不是逐行插入(这在 ClickHouse 中是反模式),而是批量写入数据。
import clickhouse_connect
import pandas as pd
# Connect to our local ClickHouse instance via Docker
client = clickhouse_connect.get_client(host='localhost', port=8123, username='default')
def ingest_wearable_data(df: pd.DataFrame):
"""
Ingests a Pandas DataFrame into ClickHouse.
Expects columns: ['event_time', 'metric_name', 'value', 'source_device', 'user_id', 'tags']
"""
print(f"🚀 Ingesting {len(df)} rows of data...")
# ClickHouse loves batches!
client.insert_df('health_metrics', df)
print("✅ Ingestion complete.")
# Example: Processing Oura Sleep Data
# df = pd.read_json('oura_sleep_data.json')
# ingest_wearable_data(df)
示例查询:睡眠期间的 HRV
SELECT
toStartOfDay(event_time) AS day,
avg(value) AS avg_hrv,
quantile(0.9)(value) AS p90_hrv
FROM health_metrics
WHERE metric_name = 'HRV'
AND tags HAS 'sleep'
GROUP BY day
ORDER BY day DESC
LIMIT 30;
即使在 5000 万行数据的情况下,这个查询通常也能在 50 毫秒以内返回结果。 🏎️
可扩展性考虑
虽然此设置在本地运行良好,但生产级健康数据平台必须能够处理:
- 模式演进
- 多租户
- 睡眠与活动指标之间的复杂连接模式
想了解更多面向生产的示例以及高级数据工程模式——例如集成 AI 驱动的健康洞察或构建事件驱动架构——请查阅 WellAlly Tech Blog 上的深度文章。这是工程师们弥合 “在我的机器上可用” 与 “数百万用户都能使用” 差距的绝佳资源。
使用 Apache Superset 可视化
为了让数据更易于阅读,连接 Apache Superset 到你的 ClickHouse 实例:
- 使用
clickhouse://驱动添加一个新的数据库连接。 - 创建一个 时间序列图表。
- 将
event_time设为时间列。
Boom! 现在你已经拥有了一个专业级的健康仪表盘,堪比 Oura 和 Apple Health 应用本身。
结论
Quantifying yourself shouldn’t be limited by your tools. By moving from legacy databases to ClickHouse, you unlock the ability to query years of biometric data in the blink of an eye.
您在追踪什么?血糖水平、HRV,还是您的编码生产力指标?在下方留下评论,让我们聊聊数据!
If you enjoyed this tutorial, don’t forget to ❤️ and 🦄. For more advanced tutorials on data pipelines and system architecture, visit the WellAlly Blog.