数据库和数据表(最新20260120)
— dawn
一、 主控指挥库 (pioneer_main.db)
职责:管理 SaaS 运营、会员权限、全局卡密以及“全球心智(词库自进化)”。
二、 用户私有资产库 (user_{id}.db)
职责:物理隔离存储每个用户的关键词资产。采用**“三表分流 + 一图全息”**的架构。
1. 物理表 A:user_keywords (身份主表)
只存最核心的、不可变的身份标识。
- id: 自增 ID。
- keyword: 原始关键词文本。
- fingerprint: 唯一语义指纹 (由 Token-Sort-Hash 生成)。
- is_master_record: 是否为同指纹组中的价值最高词(母词)。
- industry_tag: 所属行业标签(如 ebike)。
- sample_origin: 数据来源(文件名)。
- last_analyzed_at: 最后一次精算时间。
2. 物理表 B:keyword_metrics (数值指标表)
存放所有需要数学运算的 REAL/INTEGER 字段(由 SystemDoctor 路由)。
- 基础指标:volume, cpc, competition。
- 精算指标:total_value, action_priority, g_kei, real_potential。
- 趋势指标:momentum_score, three_month_change, yoy_change。
- SEO/Ads指标:seo_difficulty, ad_density_score, buying_power_index, yield_index。
3. 物理表 C:keyword_attributes (策略属性表)
存放所有 TEXT 类型的 AI 推演、分类、路径和建议。
- 语义特征:intent, strategy, task_archetype, persona。
- 内容架构:topic_level, topic_cluster, recommended_silo_path, target_canonical。
- 零件特征:attr_specs_core, attr_actions_core, visual_synergy。
- 风险评估:ai_risk, profit_status, attr_friction_type。
4. 逻辑视图:v_keyword_full (2026 全息全维度视图)
- 实现方式:由 models.py 动态生成 SQL,通过 fingerprint 将上述三张表 LEFT JOIN。
- UI 应用:所有的前端表格、资产仓库、下载导出,全部只读取这个视图,不直接读物理表。
三、 核心逻辑闭环 (互不拆台的保障)
- 分流存储 (The Split):
当 ExpertAnalyzer 计算出 120 维度结果后,AssetCRUD 会调用 SystemDoctor.get_target_table,把 cpc 塞进表 B,把 intent 塞进表 C。 - 法医级渲染 (Safe Render):
MasterAppTables 在显示数据时,会比对列名:- 如果在 SystemDoctor.METRICS_FIELDS 中,且列名不含 HTML -> 按数字或金额格式化。
- 如果不在其中 -> 按原始文本或 HTML 渲染。
- 心智同步 (The Sync):
管理员在后台把 wholesale 定位为 b2b。点击同步后,系统直接修改所有用户库物理表 A(user_keywords.intent),视图 v_keyword_full 会自动感应并刷新,用户看到的 120 维度精度瞬间提升。
1. 宪法层:定义字段(Source of Truth)
- 文件:core/registry.py
- 作用:决定了系统中有哪些维度。
- 决定内容:字段名称(如 buying_power_index)、数据类型(REAL/TEXT)、默认值(0.0/"-")、以及该维度的 UI 标签。
- 逻辑:所有其他文件都必须引用这里的 DIMENSION_REGISTRY 字典,它是所有数据的源头。
2. 蓝图层:物理建表(Physical Schema)
- 文件:database/models.py
- 作用:决定了数据在硬盘上长什么样。
- 决定内容:
- 它定义了三张物理表的固定骨架:user_keywords(身份)、keyword_metrics(数值)、keyword_attributes(属性)。
- 它定义了全息视图 v_keyword_full 的“缝合”方式(即通过 fingerprint 将三张表左连接)。
- 关键点:视图的 SQL 语句是由这个文件动态生成的。
3. 执法层:分流路由(The Traffic Cop)
- 文件:system_doctor.py
- 作用:决定了某个字段该存进哪张表。
- 决定内容:内部的 get_target_table(field_name) 方法。
- 逻辑:当你输入 total_value 时,它告诉系统“这是指标,去 keyword_metrics”;当你输入 strategy 时,它说“这是文本,去 keyword_attributes”。
- 风险点:如果这个文件的路由逻辑改了,数据库就会找不到列,产生 no such column 报错。
4. 施工层:读写执行(Persistence Engine)
- 文件:database/crud/assets.py
- 作用:决定了数据如何进出。
- 决定内容:
- upsert_keywords:负责把分析完的一大条数据,按照 Doctor 的路由,拆分成三份存入物理表。
- search_assets:负责从全息视图中把数据完整取出来。
- 关键点:它实现了 120 维度数据的物理落地。
5. 表现层:数据渲染(Presentation Layer)
- 文件:ui/app_exclusive/tables.py
- 作用:决定了数据如何显示。
- 决定内容:SafeRender 方法。
- 逻辑:它拿到视图里的原始值(如 81440),根据列名(如 volume)决定不加符号,或者根据列名(如 cpc)决定加 $。
- 纠偏点:之前的 $Volume 错误就是在这里的判定逻辑出了偏差,需要通过硬编码白名单来矫正。
特殊逻辑文件:L5 架构矩阵
- 文件:core/clustering/hierarchical.py
- 作用:决定了 L5 模式下的逻辑结构。
- 关联:它不改变物理表结构,但它决定了如何将物理数据“横向展开”成 UI 看到的矩阵报表。
总结:数据结构稳定的标准
当这 5 个文件达成以下共识时,你的数据结构就彻底稳定了:
- Registry 说:我有 120 个字段。
- Models 说:我已经按 Registry 的类型分好了三张表,并建好了视图。
- Doctor 说:我有一张地图,知道这 120 个字段分别属于哪张表。
- CRUD 说:我按 Doctor 的地图存,按 Models 的视图取。
- Tables 说:我知道哪些字段是钱,哪些是数字,我按 Registry 的字段名精准打标渲染。
如果你不想再改数据结构,以后只需根据 Registry 里的定义,微调 SystemDoctor 的路由归类即可。
新增维度的方法
第一步:宪法备案 (修改 core/registry.py)
在 DIMENSION_REGISTRY 字典中添加新字段的定义。这是所有逻辑的源头。
codePython
# core/registry.py
DIMENSION_REGISTRY = OrderedDict({
# ... 原有维度 ...
"brand_loyalty": ("REAL", 0.0, "品牌忠诚度分", "show_expert_dims"),
})第二步:路径指派 (修改 system_doctor.py)
决定这个新维度在物理上存放在哪张表。
- 如果是数值/指标(REAL/INTEGER):将其加入 METRICS_FIELDS 集合。
- 如果是文本/建议(TEXT):它会自动路由到 keyword_attributes(根据 get_target_table 的默认逻辑)。
codePython
# system_doctor.py
class SystemDoctor:
METRICS_FIELDS = {
# ... 原有字段 ...
'brand_loyalty', # 🚀 显式指派到数值表
}第三步:物理扩容 (执行 system_doctor.py)
由于物理数据库文件(.db)已经生成,新增维度需要手动触发一次“物理手术”来补齐列,并更新全息视图。
操作:在终端运行:
codeBash
python system_doctor.py- 原理:heal_database() 会检测到物理表缺了 brand_loyalty,自动执行 ALTER TABLE ADD COLUMN,并重新运行 DROP/CREATE VIEW,让视图 v_keyword_full 包含这一列。
第四步:算力实现 (修改对应的 calculator)
在分析流中计算出这个维度的具体值。
codePython
# core/calculators/expert_dimension.py (举例)
class ExpertDimensionCalculator(BaseCalculator):
def process(self, df: pl.DataFrame) -> pl.DataFrame:
# ... 计算逻辑 ...
df = df.with_columns([
pl.lit(85.5).alias("brand_loyalty") # 假设的计算结果
])
return df第五步:权限与渲染 (自动对齐)
- 权限:在 services/security_service.py 的 TierGate.FIELD_MAP 中将新字段归口到某个权限包(如 show_expert_dims)。
- 渲染:由于你在 ui/app_exclusive/tables.py 中已经使用了白名单机制:
- 因为 brand_loyalty 已经加入了 SystemDoctor.METRICS_FIELDS。
- SafeRender 会自动识别它是一个指标,从而进行数值格式化。
- 无需修改 Table 渲染代码,它会自动显示在前端。
💡 为什么这套方法能“锁定架构”?
- Models 不动:database/models.py 内部是通过 for col in DIMENSION_REGISTRY 循环的,只要 Registry 变了,它生成的 SQL 蓝图自动就变了。
- CRUD 不动:AssetCRUD 存数据时会问 SystemDoctor 去哪,Doctor 说去 A 表,它就去 A 表。
- Tables 不动:SafeRender 是通过对比列名和 Doctor 的白名单来工作的,新维度只要在 Doctor 那里报了备,渲染器就认领。
总结
以后增加任何数据精度,只需要:
1. Registry 注册 -> 2. Doctor 报备 -> 3. 运行 Doctor 补齐物理列 -> 4. Calculator 算数。
这套流程保证了你永远不会因为新增字段而把现有的数据库弄乱。