Files
geo/docs/question-driven-monitoring-design-v1.md
T
root de30497f59 feat: add tenant and user management with migrations, handlers, and tests
- Implemented tenant and user management features including:
  - Tenant creation and management with associated migrations.
  - User creation and management with associated migrations.
  - Tenant membership management with associated migrations.
  - Platform user roles management with associated migrations.
  - Quota management with associated migrations.
  - Article and template management with associated migrations.
- Added HTTP handlers for templates and workspaces.
- Created tests for protected and public routes.
- Introduced a script to check tenant scope in SQL queries.
- Documented task plan for backend completion and frontend foundation.
2026-04-01 00:58:42 +08:00

10 KiB

GEO 平台问题驱动的数据监控设计 V1

1. 文档信息

项目 内容
文档名称 GEO 平台问题驱动的数据监控设计 V1
文档版本 V1.0
文档状态 待评审
创建日期 2026-03-25
适用范围 品牌词库、问题集、数据追踪页
关联文档 docs/geo-platform-prd-v1.md
关联文档 docs/geo-platform-tech-architecture-v1-50k.md

2. 设计背景

当前数据监控页不是通用 BI,而是明确来源于:

  • 品牌
  • 关键词
  • 关键词下的问题集
  • 模型
  • 最近 30 天时间窗口

因此,数据监控的真实逻辑源头不是“文章”本身,也不是“关键词”本身,而是:

  • 品牌关键词下配置的问题
  • 系统按周期执行这些问题后的模型回答结果

这意味着整套监控系统必须按“问题驱动”来设计,否则后续会出现:

  • 指标口径不清
  • 历史数据与问题版本混淆
  • 任务量失控
  • 查询逻辑和数据模型对不上

3. 核心结论

V1 建议采用以下原则:

  1. 问题 是监控数据的最小采集单元。
  2. 关键词 只是问题集合的容器和聚合维度。
  3. 品牌监控页 展示的是问题运行结果的聚合视图。
  4. 历史数据必须绑定问题版本,不能因为改了问题文案就覆盖历史口径。
  5. 页面查询只查汇总表,不扫描原始问答记录。

4. 页面逻辑拆解

结合当前页面,用户选择条件是:

  • 品牌
  • 关键词
  • 模型
  • 时间范围,最多近 30 天

页面展示内容包括:

  • 提及率
  • 首位提及率
  • 首选推荐率
  • 正面提及率
  • 日趋势折线
  • 高频问题
  • 引用排行榜

这些数据不应该直接从原始问答明细实时计算,而应该来自预聚合结果。

5. 数据采集逻辑

5.1 问题来源

问题来源于品牌词库中的关键词问题集。

例如:

  • 品牌:12
  • 关键词:数字时尚
  • 问题:
    • 数字时尚品牌有哪些值得关注的新趋势
    • 如何选择适合自己的数字时尚单品
    • 数字时尚和传统时尚的主要区别是什么

这些问题是监控任务的输入,不是单纯展示内容。

5.2 采集单元

建议将一次监控采集定义为:

  • 一个问题
  • 一个模型
  • 一次执行时间

即:

1 question x 1 model x 1 run_time = 1 条原始监控记录

5.3 指标来源

每次模型回答返回后,系统进行解析,得到结构化结果:

  • 是否提及品牌
  • 是否首位提及品牌
  • 是否首选推荐品牌
  • 情感倾向是否正向
  • 是否引用系统文章
  • 引用了哪篇文章

然后再做日级汇总。

6. 推荐数据模型

6.1 主数据表

brand_keywords

  • id
  • brand_id
  • name
  • status
  • created_at

brand_questions

  • id
  • brand_id
  • keyword_id
  • current_version_id
  • status
  • created_at

说明:

  • 一条问题属于一个品牌和一个关键词
  • 数据监控页中的“高频问题”和“问题集”都可以从这里关联出来

brand_question_versions

  • id
  • question_id
  • question_text
  • question_hash
  • version_no
  • is_active
  • created_at

说明:

  • 问题文案一旦修改,新增版本,不覆盖历史版本
  • 历史监控记录绑定到具体 question_version_id

6.2 原始采集表

question_monitor_runs

  • id
  • brand_id
  • keyword_id
  • question_id
  • question_version_id
  • model_id
  • run_date
  • run_at
  • task_batch_id
  • status
  • raw_answer_storage_key
  • created_at

说明:

  • 一次执行一条记录
  • 模型原始回答建议放对象存储,数据库只存引用路径和摘要字段

question_monitor_parse_results

  • id
  • run_id
  • mentioned_brand
  • top1_mentioned
  • first_recommended
  • positive_mentioned
  • citation_article_count
  • citation_platform_count
  • parser_version
  • created_at

说明:

  • 解析结果是后续聚合的直接来源

6.3 汇总表

question_model_daily_metrics

粒度:

  • brand_id + keyword_id + question_id + question_version_id + model_id + date

字段:

  • ask_count
  • mention_count
  • top1_mention_count
  • first_recommend_count
  • positive_mention_count
  • citation_count
  • updated_at

用途:

  • 回看单个问题在每天的表现
  • 支撑高频问题排行和问题详情

keyword_model_daily_metrics

粒度:

  • brand_id + keyword_id + model_id + date

字段:

  • question_count
  • ask_count
  • mention_count
  • top1_mention_count
  • first_recommend_count
  • positive_mention_count
  • citation_count
  • mention_rate
  • top1_mention_rate
  • first_recommend_rate
  • positive_mention_rate
  • updated_at

用途:

  • 直接支撑你截图里的 30 天趋势和顶部指标卡

keyword_model_top_questions_daily

粒度:

  • brand_id + keyword_id + model_id + date + question_id

字段:

  • question_text_snapshot
  • ask_count
  • mention_count
  • score

用途:

  • 支撑右侧“高频问题”

keyword_model_citation_rank_daily

粒度:

  • brand_id + keyword_id + model_id + date + cited_article_id

字段:

  • citation_count
  • citation_rate

用途:

  • 支撑引用排行榜

7. 查询口径定义

7.1 顶部指标卡

以所选:

  • 品牌
  • 关键词
  • 模型
  • 时间范围

为过滤条件,从 keyword_model_daily_metrics 汇总得出:

  • 提及率 = sum(mention_count) / sum(ask_count)
  • 首位提及率 = sum(top1_mention_count) / sum(ask_count)
  • 首选推荐率 = sum(first_recommend_count) / sum(ask_count)
  • 正面提及率 = sum(positive_mention_count) / sum(ask_count)

7.2 趋势图

直接查询 keyword_model_daily_metrics 最近 30 天数据。

每个点只是一行日汇总,查询量很小。

7.3 高频问题

keyword_model_top_questions_daily 取最近 30 天累计 TopN。

7.4 引用排行榜

keyword_model_citation_rank_daily 取最近 30 天累计 TopN。

8. 任务调度设计

8.1 为什么要控制任务量

监控任务量不是由页面访问量决定,而是由:

  • 品牌数
  • 每个品牌下关键词数
  • 每个关键词下问题数
  • 模型数
  • 每天执行次数

共同决定。

8.2 数据量公式

每日原始采集量近似为:

品牌数 x 每品牌关键词数 x 每关键词问题数 x 模型数 x 每日执行次数

例如:

轻量场景

  • 50 个品牌
  • 每品牌 10 个关键词
  • 每关键词 10 个问题
  • 5 个模型
  • 每天 1 次

则:

50 x 10 x 10 x 5 x 1 = 25,000 条/天

中等场景

  • 100 个品牌
  • 每品牌 20 个关键词
  • 每关键词 20 个问题
  • 5 个模型
  • 每天 2 次

则:

100 x 20 x 20 x 5 x 2 = 400,000 条/天

如果每条原始回答按 5KB 估算:

  • 每天约 2GB 原始文本
  • 30 天约 60GB 原始文本

因此:

  • 原始回答不建议长期放 PostgreSQL
  • 建议放对象存储
  • PostgreSQL 只保存解析结果和汇总结果

8.3 V1 推荐执行频率

为了控制数据量,V1 建议:

  • 每个问题每天默认执行 1 次
  • 重要品牌或付费用户可提升为 2 次
  • 不建议 V1 做高频小时级轮询

8.4 去重策略

如果同一品牌下多个关键词出现完全相同的问题文案,建议:

  • 通过 question_hash 检测重复问题
  • 同一品牌、同一模型、同一天内同 hash 的问题尽量复用一次执行结果

但聚合归属仍可按映射关系分别记账。

这样可以显著减少任务量。

9. 版本与历史口径

9.1 为什么必须版本化

如果用户把问题:

  • “数字时尚品牌有哪些值得关注的新趋势”

改成:

  • “2026 年数字时尚品牌有哪些值得关注的新趋势”

那前后两者其实已经不是同一个监控口径。

如果直接覆盖旧问题,历史趋势就会失真。

9.2 推荐做法

  • 问题修改时新建 question_version
  • 新运行记录绑定到新版本
  • 历史数据仍归属旧版本
  • 页面默认展示当前版本问题的聚合数据

如果要做历史总览,可按 question_id 聚合,但需要在文档里说明“跨版本聚合”。

10. 页面查询策略

10.1 页面不查原始表

数据页不能直接查:

  • question_monitor_runs
  • question_monitor_parse_results

这些表只用于:

  • 问题详情
  • badcase 回放
  • 算法验证

10.2 页面只查汇总表

数据页查询路径应为:

  1. 先查 Redis
  2. Redis miss 后查 PostgreSQL 汇总表
  3. 后台异步更新缓存

10.3 Redis Key 建议

可按以下维度缓存:

  • brand:{brand_id}:keyword:{keyword_id}:model:{model_id}:range:30d:summary
  • brand:{brand_id}:keyword:{keyword_id}:model:{model_id}:range:30d:trend
  • brand:{brand_id}:keyword:{keyword_id}:model:{model_id}:range:30d:top_questions
  • brand:{brand_id}:keyword:{keyword_id}:model:{model_id}:range:30d:citation_rank

11. V1 性能判断

针对当前页面,如果采用“按问题采集、按天汇总、按 30 天查询”的模型,PostgreSQL 是够用的。

原因是:

  • 页面查询只查 30 天汇总数据
  • 每次查询最多几十到几百行
  • 高频问题和排行榜都可提前汇总
  • Redis 可以承接高频重复查询

真正可能变大的不是页面查询,而是:

  • 原始问题执行任务量
  • 原始模型回答存储量

所以要重点控制的是任务调度和原始结果留存,而不是页面 SQL 本身。

12. V1 推荐保留策略

建议:

  • 原始运行记录保留 30 ~ 90 天
  • 原始回答正文放对象存储
  • PostgreSQL 解析结果保留 90 天
  • 日级汇总表保留 180 天 或更久

如果页面只看 30 天,也建议汇总表多保留一段时间,方便后续扩展。

13. 升级边界

当出现以下情况时,再升级架构:

  • 问题量暴涨
  • 模型数明显增加
  • 每日执行次数明显增加
  • 页面支持自由筛选、明细钻取
  • 监控维度从 30 天扩展到半年、一年

此时可以逐步升级为:

  • 独立分析库
  • 更大规模任务调度
  • 更复杂的去重复用逻辑
  • 专用分析引擎

14. V1 最终建议

结合你当前页面和品牌词库结构,V1 最合理的设计是:

  1. 问题 为最小监控采集单元。
  2. 关键词 作为问题的聚合容器。
  3. 问题版本 保证历史口径稳定。
  4. 日级汇总表 支撑页面查询。
  5. 对象存储 保存原始回答,避免 PostgreSQL 膨胀。
  6. 问题 hash 去重 控制执行量。
  7. 默认每题每天执行 1 次,避免 V1 数据量失控。

这样做,逻辑、数据量、页面性能三者才能对齐。