This commit is contained in:
Neo
2026-02-04 21:39:01 +08:00
parent ee773a9b52
commit a3f4d04335
148 changed files with 31455 additions and 182 deletions

View File

@@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
"""
创建指数算法相关表
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config.settings import AppConfig
from database.connection import DatabaseConnection
from database.operations import DatabaseOperations
# 表DDL
DDL_STATEMENTS = [
# 参数配置表
"""
DROP TABLE IF EXISTS billiards_dws.cfg_index_parameters CASCADE;
CREATE TABLE billiards_dws.cfg_index_parameters (
param_id SERIAL PRIMARY KEY,
index_type VARCHAR(50) NOT NULL,
param_name VARCHAR(100) NOT NULL,
param_value NUMERIC(14,6) NOT NULL,
description TEXT,
effective_from DATE NOT NULL DEFAULT CURRENT_DATE,
effective_to DATE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_cfg_index_parameters UNIQUE (index_type, param_name, effective_from)
);
CREATE INDEX idx_cfg_index_params_type ON billiards_dws.cfg_index_parameters (index_type);
""",
# 召回指数表
"""
DROP TABLE IF EXISTS billiards_dws.dws_member_recall_index CASCADE;
CREATE TABLE billiards_dws.dws_member_recall_index (
recall_id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
tenant_id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
days_since_last_visit INTEGER,
visit_interval_median NUMERIC(10,2),
visit_interval_mad NUMERIC(10,2),
days_since_first_visit INTEGER,
days_since_last_recharge INTEGER,
visits_last_14_days INTEGER NOT NULL DEFAULT 0,
visits_last_60_days INTEGER NOT NULL DEFAULT 0,
score_overdue NUMERIC(10,4),
score_new_bonus NUMERIC(10,4),
score_recharge_bonus NUMERIC(10,4),
score_hot_drop NUMERIC(10,4),
raw_score NUMERIC(14,6),
display_score NUMERIC(4,2),
calc_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
calc_version INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_dws_member_recall UNIQUE (site_id, member_id)
);
CREATE INDEX idx_dws_recall_display ON billiards_dws.dws_member_recall_index (site_id, display_score DESC);
""",
# 亲密指数表
"""
DROP TABLE IF EXISTS billiards_dws.dws_member_assistant_intimacy CASCADE;
CREATE TABLE billiards_dws.dws_member_assistant_intimacy (
intimacy_id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
tenant_id BIGINT NOT NULL,
member_id BIGINT NOT NULL,
assistant_id BIGINT NOT NULL,
session_count INTEGER NOT NULL DEFAULT 0,
total_duration_minutes INTEGER NOT NULL DEFAULT 0,
basic_session_count INTEGER NOT NULL DEFAULT 0,
incentive_session_count INTEGER NOT NULL DEFAULT 0,
days_since_last_session INTEGER,
attributed_recharge_count INTEGER NOT NULL DEFAULT 0,
attributed_recharge_amount NUMERIC(14,2) NOT NULL DEFAULT 0,
score_frequency NUMERIC(10,4),
score_recency NUMERIC(10,4),
score_recharge NUMERIC(10,4),
score_duration NUMERIC(10,4),
burst_multiplier NUMERIC(6,4),
raw_score NUMERIC(14,6),
display_score NUMERIC(4,2),
calc_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
calc_version INTEGER NOT NULL DEFAULT 1,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_dws_member_assistant_intimacy UNIQUE (site_id, member_id, assistant_id)
);
CREATE INDEX idx_dws_intimacy_member ON billiards_dws.dws_member_assistant_intimacy (site_id, member_id, display_score DESC);
CREATE INDEX idx_dws_intimacy_assistant ON billiards_dws.dws_member_assistant_intimacy (site_id, assistant_id, display_score DESC);
""",
# 分位点历史表
"""
DROP TABLE IF EXISTS billiards_dws.dws_index_percentile_history CASCADE;
CREATE TABLE billiards_dws.dws_index_percentile_history (
history_id BIGSERIAL PRIMARY KEY,
site_id BIGINT NOT NULL,
index_type VARCHAR(50) NOT NULL,
calc_time TIMESTAMPTZ NOT NULL,
percentile_5 NUMERIC(14,6),
percentile_95 NUMERIC(14,6),
percentile_5_smoothed NUMERIC(14,6),
percentile_95_smoothed NUMERIC(14,6),
record_count INTEGER,
min_raw_score NUMERIC(14,6),
max_raw_score NUMERIC(14,6),
avg_raw_score NUMERIC(14,6),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uk_dws_index_percentile_history UNIQUE (site_id, index_type, calc_time)
);
CREATE INDEX idx_dws_percentile_history ON billiards_dws.dws_index_percentile_history (site_id, index_type, calc_time DESC);
"""
]
# 初始化参数
SEED_PARAMS = """
INSERT INTO billiards_dws.cfg_index_parameters
(index_type, param_name, param_value, description, effective_from)
VALUES
('RECALL', 'lookback_days', 60, '回溯窗口(天)', CURRENT_DATE),
('RECALL', 'sigma_min', 2.0, '波动下限(天)', CURRENT_DATE),
('RECALL', 'halflife_new', 7, '新客户半衰期(天)', CURRENT_DATE),
('RECALL', 'halflife_recharge', 10, '刚充值半衰期(天)', CURRENT_DATE),
('RECALL', 'weight_overdue', 3.0, '超期紧急性权重', CURRENT_DATE),
('RECALL', 'weight_new', 1.0, '新客户权重', CURRENT_DATE),
('RECALL', 'weight_recharge', 1.0, '刚充值权重', CURRENT_DATE),
('RECALL', 'weight_hot', 1.0, '热度断档权重', CURRENT_DATE),
('RECALL', 'percentile_lower', 5, '下锚分位数', CURRENT_DATE),
('RECALL', 'percentile_upper', 95, '上锚分位数', CURRENT_DATE),
('RECALL', 'ewma_alpha', 0.2, 'EWMA平滑系数', CURRENT_DATE),
('INTIMACY', 'lookback_days', 60, '回溯窗口(天)', CURRENT_DATE),
('INTIMACY', 'session_merge_hours', 4, '会话合并间隔(小时)', CURRENT_DATE),
('INTIMACY', 'recharge_attribute_hours', 1, '充值归因窗口(小时)', CURRENT_DATE),
('INTIMACY', 'amount_base', 500, '金额压缩基准(元)', CURRENT_DATE),
('INTIMACY', 'incentive_weight', 1.5, '附加课权重倍数', CURRENT_DATE),
('INTIMACY', 'halflife_session', 14, '会话衰减半衰期(天)', CURRENT_DATE),
('INTIMACY', 'halflife_last', 10, '最近一次半衰期(天)', CURRENT_DATE),
('INTIMACY', 'halflife_recharge', 21, '充值衰减半衰期(天)', CURRENT_DATE),
('INTIMACY', 'halflife_short', 7, '短期激增检测半衰期(天)', CURRENT_DATE),
('INTIMACY', 'halflife_long', 30, '长期激增检测半衰期(天)', CURRENT_DATE),
('INTIMACY', 'weight_frequency', 2.0, '频次权重', CURRENT_DATE),
('INTIMACY', 'weight_recency', 1.5, '最近一次权重', CURRENT_DATE),
('INTIMACY', 'weight_recharge', 2.0, '归因充值权重', CURRENT_DATE),
('INTIMACY', 'weight_duration', 0.5, '时长权重', CURRENT_DATE),
('INTIMACY', 'burst_gamma', 0.6, '激增放大系数', CURRENT_DATE),
('INTIMACY', 'percentile_lower', 5, '下锚分位数', CURRENT_DATE),
('INTIMACY', 'percentile_upper', 95, '上锚分位数', CURRENT_DATE),
('INTIMACY', 'ewma_alpha', 0.2, 'EWMA平滑系数', CURRENT_DATE)
ON CONFLICT (index_type, param_name, effective_from) DO NOTHING;
"""
def main():
print("创建指数算法相关表...")
config = AppConfig.load()
db_conn = DatabaseConnection(config.config["db"]["dsn"])
try:
with db_conn.conn.cursor() as cur:
# 创建表
for i, ddl in enumerate(DDL_STATEMENTS, 1):
print(f" 执行DDL {i}/{len(DDL_STATEMENTS)}...")
cur.execute(ddl)
# 初始化参数
print(" 初始化算法参数...")
cur.execute(SEED_PARAMS)
db_conn.conn.commit()
print("完成!")
# 验证
cur.execute("SELECT COUNT(*) FROM billiards_dws.cfg_index_parameters")
count = cur.fetchone()[0]
print(f" 已插入 {count} 个参数配置")
finally:
db_conn.close()
if __name__ == '__main__':
main()