ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

PostHog 数据查询指南:深入解析 `system.session_recordings` 会话录制元数据模型

PostHog 数据查询指南:深入解析 `system.session_recordings` 会话录制元数据模型 PostHog 数据查询指南深入解析system.session_recordings会话录制元数据模型【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog导读system.session_recordings是 PostHog 中用于检索、过滤会话录制Session Recording记录的元数据系统表它把 SDK 采集的录制信息以录制一条元数据的形式暴露给 HogQL/SQL 查询。本文以 PostHog 仓库中 querying-posthog-data 技能的 Schema 参考文档 为核心骨架结合 SessionRecording 模型源码 与配套查询示例完整讲解该表的字段语义、存储分层、关联关系与软删除处理并给出可直接运行的查询语句。读完本文你将能在posthog:execute-sql中准确列出、筛选和定位会话录制记录并理解哪些字段来自 Postgres、哪些来自 ClickHouse。一、表概览元数据在 Postgres重放数据在 ClickHouse 与对象存储官方 Schema 参考文档对system.session_recordings的定位非常明确它保存的是由 PostHog SDK 捕获的会话录制的元数据Metadata。实际的重放replay数据并不在这张表里而是存放在 ClickHouse 和对象存储中这张 Postgres 表只存储录制级的元数据供列表展示与过滤使用。从源码可以印证这一分层设计。在 SessionRecording 模型 中持久化到数据库的字段只包含录制的基本信息session_id、team、时间区间、各类计数、存储路径等而一批动态字段viewed、ongoing、activity_score、expiry_time、recording_ttl、total_size、event_count、matching_events、_metadata则不是数据库列它们由 ClickHouse 或 S3 在运行时加载填充# posthog/session_recordings/models/session_recording.py # DYNAMIC FIELDS viewed: Optional[bool] False ongoing: Optional[bool] None activity_score: Optional[float] None expiry_time: Optional[datetime] None recording_ttl: Optional[int] None total_size: Optional[int] None event_count: Optional[int] None _metadata: Optional[RecordingMetadata] None这意味着当你通过system.session_recordings查询时能可靠查询到的是 Postgres 中落库的元数据列而活动统计类字段见下节可能为 NULL——这与原文档中Activity data (click_count, duration, etc.) is populated from ClickHouse and may be NULL for older recordings的提示完全一致。两条数据通路模型中的load_metadata()方法源码位置展示了元数据的两种来源V2 录制路径full_recording_v2_path非空元数据已完整持久化在模型/Postgres 中无需额外加载旧版录制路径通过SessionReplayEvents().get_metadata(...)从ClickHouse拉取元数据再回填distinct_id、start_time、end_time、duration、click_count、keypress_count、active_seconds、inactive_seconds、各类 console 计数、retention_period_days、expiry_time、recording_ttl、ongoing、total_size、event_count等字段。这正是旧录制这些字段可能为 NULL、新录制则可能是完整值的根因——历史数据没有经过 ClickHouse 元数据回填流程。重要语义细节源码注释明确指出active_seconds是对各时间块活跃时间的求和当同一会话存在并发标签页时各块活跃时间会各自计数因此总活跃秒数可能超过实际墙钟时长而由于只存储了汇总值这部分重叠无法再被扣除。在基于该字段做统计口径时需注意这一点。二、核心字段Columns以下字段来自SessionRecordingDjango 模型的实际定义源码位置即system.session_recordings表所暴露的列system.*表暴露的是各 Django 模型的精选子集因此请以本表为准而非 REST 返回的字段形状。字段类型源码语义说明idUUIDT主键内部主键使用 PostHog 标准的 UUIDT 生成session_idCharField(unique, max_length200)面向用户的录制 ID用于 URL 与 API 调用由 posthog-js 生成与内部id不同注意区分team_idForeignKey → Team录制所属团队on_deleteCASCADE删除团队级联删除录制created_atDateTimeField(auto_now_add)元数据行创建时间可能为 NULLdeletedBooleanField(nullTrue)软删除标记整数语义 0/1旧行可能为 NULLobject_storage_pathCharField(max_length200)旧版录制对象存储路径可能为 NULLfull_recording_v2_pathCharField(max_length1000)V2 录制完整数据路径非空时元数据已完整落库distinct_idCharField(max_length400)关联到用户person的标识用于与 persons 表关联durationIntegerField录制总时长秒来自 ClickHouse旧录制可能为 NULLactive_secondsIntegerField活跃秒数见上文重叠语义inactive_secondsIntegerField非活跃秒数源码计算为max(duration - active_seconds, 0)start_time/end_timeDateTimeField录制开始/结束时间来自 ClickHouseclick_count/keypress_count/mouse_activity_countIntegerField点击、按键、鼠标活动计数来自 ClickHouseconsole_log_count/console_warn_count/console_error_countIntegerField控制台日志/警告/错误计数来自 ClickHousestart_urlCharField(max_length512)录制起始 URL截断至 512 字符去查询参数storage_versionCharField(max_length20)存储版本标识retention_period_daysIntegerField录制保留天数来自 ClickHousesession_idvsid最容易踩的坑原文档专门强调session_id是面向用户的 ID用于 URL 和 API 调用而不是内部id。从源码注释可以进一步理解其来历源码位置session_id由 posthog-js 中的独立工具生成非 UUIDT 标准并作为唯一键uniqueTrue保存用于与其他录制相关模型建立关联模型同时创建 UUIDT 格式的内部id和唯一的session_id字段以保持向后兼容所有与会话录制相关的其他模型如播放列表关联、已查看记录都通过这个唯一的session_id建立链接。因此在查询中如果你要通过 API/UI 拿到的 ID 反查录制应使用session_id进行过滤而不是id。三、关键关联关系Key Relationships原文档列出三条核心关联对应源码中的外键与查询模式每个录制属于一个团队team_idSessionRecording.team ForeignKey(Team, on_deleteCASCADE)源码位置。查询时务必用team_id限定范围避免跨团队数据串扰。录制通过distinct_id关联到用户录制本身不直接存 person 外键而是通过distinct_id与 persons 关联。源码中load_person()源码位置通过 personhog 客户端按distinct_id解析出 Person。因此 SQL 联查时应使用system.session_recordings.distinct_id与 persons 侧匹配。录制可被加入 Session Recording Playlists通过SessionRecordingPlaylistItem关联该关联表未作为系统表暴露。播放列表本身的元数据模型见 models-session-recording-playlists.md.j2播放列表分为collection手动精选集合与filters按保存的筛选条件动态匹配两种类型。四、重要注意事项与查询实践4.1 录制由 SDK 创建而非 API原文档明确Recordings are created by the SDK, not via the API。即你不能通过 API 往这张表里写入一条录制——录制生命周期完全由 PostHog SDK如 posthog-js在浏览器/客户端捕获并上报触发。系统表中的行是采集流程的产物查询侧只读。4.2 软删除过滤ifNull(deleted, 0) 0deleted字段是整数语义的 0/1且旧行可能为 NULL源码中deleted BooleanField(nullTrue, blankTrue)。因此标准过滤写法是SELECT session_id, start_time, duration, active_seconds, click_count FROM system.session_recordings WHERE team_id 1 AND ifNull(deleted, 0) 0 ORDER BY start_time DESC LIMIT 20不要直接写WHERE deleted 0——那会把deleted IS NULL的旧录制排除在结果之外。4.3 活动统计字段可能为 NULLclick_count、duration、active_seconds、console 系列计数等字段由 ClickHouse 回填见第一节的数据通路对旧录制可能为 NULL。在聚合前建议用coalesce/ifNull处理例如SELECT session_id, ifNull(active_seconds, 0) AS active_seconds, ifNull(click_count, 0) AS clicks FROM system.session_recordings WHERE team_id 1 AND ifNull(deleted, 0) 0 AND ifNull(active_seconds, 0) 5 ORDER BY active_seconds DESC4.4 联查用户persons按distinct_id关联到人员信息SELECT r.session_id, r.start_time, r.duration, p.properties[email] AS email FROM system.session_recordings AS r LEFT JOIN persons AS p ON p.id r.distinct_id WHERE r.team_id 1 AND ifNull(r.deleted, 0) 0 LIMIT 50提示persons 属性分事件时点与查询时点两种模式涉及person.properties.*语义时请先阅读 person-property-modes 参考。4.5 使用录制查询RecordingsQuery过滤活动指标对于列出某段时间内活跃时长超过 N 秒的录制这类需求技能库提供了标准的录制查询示例example-session-replay.md.j2核心参数为-- RecordingsQuery 语义经渲染后的 HogQL/SQL 形态 -- order: start_timeorder_direction: DESC -- date_from: -3d近 3 天 -- having_predicates: [{type: recording, key: active_seconds, value: 5, operator: gt}] -- filter_test_accounts: falseoperand: ANDlimit: 20即按start_time倒序取近 3 天、active_seconds 5、排除测试账号后最多 20 条录制。这类带活动过滤的录制列表正是system.session_recordings与 ClickHouse 活动数据配合使用的典型场景。4.6 定位单条录制并获取完整实体按 SKILL.md 的实体查找流程当需要定位一条具体录制时先用posthog:execute-sql查询system.session_recordings通过session_id或时间、团队、distinct_id 组合找到目标再用对应的只读工具如posthog:recording-get类工具按 ID 获取完整录制实体不要试图用 SQL 重建完整实体——execute-sql只用于发现/检索完整实体交给专用读取工具。SELECT session_id, start_time, duration, object_storage_path, full_recording_v2_path FROM system.session_recordings WHERE team_id 1 AND session_id 你的录制session_id AND ifNull(deleted, 0) 0五、与 Session Recording Playlists 的衔接录制与播放列表通过SessionRecordingPlaylistItem关联关联表不暴露为系统表。播放列表本身可查system.session_recording_playlists详见 播放列表 Schema 参考其中type collection表示手动精选的录制集合type filters表示保存的筛选条件会动态匹配符合条件的录制播放列表用short_id作为 API 查询键同样需要用deleted 0过滤软删除的播放列表。当你想知道某个 collection 播放列表里有哪些录制时由于关联表未暴露可从播放列表的filters字段仅typefilters时有意义反推匹配条件或通过录制侧信息与播放列表条目核对。六、实操速查表需求写法要点列出近 7 天录制WHERE team_id ? AND ifNull(deleted,0)0 AND start_time now() - INTERVAL 7 DAY过滤活跃录制AND ifNull(active_seconds, 0) 5关联用户LEFT JOIN persons AS p ON p.id r.distinct_id按session_id精查AND session_id ...勿用内部id聚合活动指标SELECT avg(ifNull(active_seconds,0)) ...先处理 NULL排除软删除一律ifNull(deleted, 0) 0延伸阅读技能总览与查询路径选择SKILL.md含 typed query 与 SQL 的选择原则、Data Schema 全表索引播放列表模型models-session-recording-playlists.md.j2录制查询示例example-session-replay.md.j2模型源码posthog/session_recordings/models/session_recording.pyHogQL 扩展含 replay 相关函数与语法hogql-extensions.md【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表