Updata2
This commit is contained in:
222
etl_billiards/scripts/test_index_tasks.py
Normal file
222
etl_billiards/scripts/test_index_tasks.py
Normal file
@@ -0,0 +1,222 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
测试指数算法任务
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加项目路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
import logging
|
||||
from config.settings import AppConfig
|
||||
from database.connection import DatabaseConnection
|
||||
from database.operations import DatabaseOperations
|
||||
from tasks.dws.index import RecallIndexTask, IntimacyIndexTask
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger('test_index')
|
||||
|
||||
def test_recall_index():
|
||||
"""测试召回指数任务"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("测试客户召回指数任务 (DWS_RECALL_INDEX)")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# 加载配置
|
||||
config = AppConfig.load()
|
||||
|
||||
# 连接数据库
|
||||
db_conn = DatabaseConnection(config.config["db"]["dsn"])
|
||||
db = DatabaseOperations(db_conn)
|
||||
|
||||
try:
|
||||
# 创建任务实例
|
||||
task = RecallIndexTask(config, db, None, logger)
|
||||
|
||||
# 执行任务
|
||||
result = task.execute(None)
|
||||
|
||||
logger.info("任务执行结果: %s", result)
|
||||
|
||||
# 查询结果
|
||||
if result.get('status') == 'success':
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(*) as total_count,
|
||||
ROUND(AVG(display_score)::numeric, 2) as avg_score,
|
||||
ROUND(MIN(display_score)::numeric, 2) as min_score,
|
||||
ROUND(MAX(display_score)::numeric, 2) as max_score,
|
||||
ROUND(AVG(raw_score)::numeric, 4) as avg_raw_score,
|
||||
ROUND(AVG(score_overdue)::numeric, 4) as avg_overdue,
|
||||
ROUND(AVG(score_new_bonus)::numeric, 4) as avg_new_bonus,
|
||||
ROUND(AVG(score_recharge_bonus)::numeric, 4) as avg_recharge_bonus,
|
||||
ROUND(AVG(score_hot_drop)::numeric, 4) as avg_hot_drop
|
||||
FROM billiards_dws.dws_member_recall_index
|
||||
"""
|
||||
rows = db.query(sql)
|
||||
if rows:
|
||||
stats = dict(rows[0])
|
||||
logger.info("-" * 40)
|
||||
logger.info("召回指数统计:")
|
||||
logger.info(" 总记录数: %s", stats['total_count'])
|
||||
logger.info(" Display Score: 平均=%.2f, 最小=%.2f, 最大=%.2f",
|
||||
stats['avg_score'] or 0, stats['min_score'] or 0, stats['max_score'] or 0)
|
||||
logger.info(" Raw Score 平均: %.4f", stats['avg_raw_score'] or 0)
|
||||
logger.info(" 分项得分平均:")
|
||||
logger.info(" - 超期紧急性: %.4f", stats['avg_overdue'] or 0)
|
||||
logger.info(" - 新客户加分: %.4f", stats['avg_new_bonus'] or 0)
|
||||
logger.info(" - 充值加分: %.4f", stats['avg_recharge_bonus'] or 0)
|
||||
logger.info(" - 热度断档: %.4f", stats['avg_hot_drop'] or 0)
|
||||
|
||||
# 查询Top 5
|
||||
logger.info("-" * 40)
|
||||
logger.info("召回优先级 Top 5:")
|
||||
top_sql = """
|
||||
SELECT member_id, display_score, raw_score,
|
||||
days_since_last_visit, visit_interval_median
|
||||
FROM billiards_dws.dws_member_recall_index
|
||||
ORDER BY display_score DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
top_rows = db.query(top_sql)
|
||||
for i, row in enumerate(top_rows or [], 1):
|
||||
r = dict(row)
|
||||
logger.info(" %d. 会员%s: %.2f分 (Raw=%.4f, 最近到店=%s天前, 周期=%.1f天)",
|
||||
i, r['member_id'], r['display_score'] or 0, r['raw_score'] or 0,
|
||||
r['days_since_last_visit'], r['visit_interval_median'] or 0)
|
||||
|
||||
return result
|
||||
|
||||
finally:
|
||||
db_conn.close()
|
||||
|
||||
|
||||
def test_intimacy_index():
|
||||
"""测试亲密指数任务"""
|
||||
logger.info("")
|
||||
logger.info("=" * 60)
|
||||
logger.info("测试客户-助教亲密指数任务 (DWS_INTIMACY_INDEX)")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# 加载配置
|
||||
config = AppConfig.load()
|
||||
|
||||
# 连接数据库
|
||||
db_conn = DatabaseConnection(config.config["db"]["dsn"])
|
||||
db = DatabaseOperations(db_conn)
|
||||
|
||||
try:
|
||||
# 创建任务实例
|
||||
task = IntimacyIndexTask(config, db, None, logger)
|
||||
|
||||
# 执行任务
|
||||
result = task.execute(None)
|
||||
|
||||
logger.info("任务执行结果: %s", result)
|
||||
|
||||
# 查询结果
|
||||
if result.get('status') == 'success':
|
||||
sql = """
|
||||
SELECT
|
||||
COUNT(*) as total_count,
|
||||
COUNT(DISTINCT member_id) as unique_members,
|
||||
COUNT(DISTINCT assistant_id) as unique_assistants,
|
||||
ROUND(AVG(display_score)::numeric, 2) as avg_score,
|
||||
ROUND(MIN(display_score)::numeric, 2) as min_score,
|
||||
ROUND(MAX(display_score)::numeric, 2) as max_score,
|
||||
ROUND(AVG(raw_score)::numeric, 4) as avg_raw_score,
|
||||
ROUND(AVG(score_frequency)::numeric, 4) as avg_frequency,
|
||||
ROUND(AVG(score_recency)::numeric, 4) as avg_recency,
|
||||
ROUND(AVG(score_recharge)::numeric, 4) as avg_recharge,
|
||||
ROUND(AVG(burst_multiplier)::numeric, 4) as avg_burst
|
||||
FROM billiards_dws.dws_member_assistant_intimacy
|
||||
"""
|
||||
rows = db.query(sql)
|
||||
if rows:
|
||||
stats = dict(rows[0])
|
||||
logger.info("-" * 40)
|
||||
logger.info("亲密指数统计:")
|
||||
logger.info(" 总记录数: %s (客户-助教对)", stats['total_count'])
|
||||
logger.info(" 唯一会员: %s, 唯一助教: %s", stats['unique_members'], stats['unique_assistants'])
|
||||
logger.info(" Display Score: 平均=%.2f, 最小=%.2f, 最大=%.2f",
|
||||
stats['avg_score'] or 0, stats['min_score'] or 0, stats['max_score'] or 0)
|
||||
logger.info(" Raw Score 平均: %.4f", stats['avg_raw_score'] or 0)
|
||||
logger.info(" 分项得分平均:")
|
||||
logger.info(" - 频次强度: %.4f", stats['avg_frequency'] or 0)
|
||||
logger.info(" - 最近温度: %.4f", stats['avg_recency'] or 0)
|
||||
logger.info(" - 充值强度: %.4f", stats['avg_recharge'] or 0)
|
||||
logger.info(" - 激增放大: %.4f", stats['avg_burst'] or 0)
|
||||
|
||||
# 查询Top亲密关系
|
||||
logger.info("-" * 40)
|
||||
logger.info("亲密度 Top 5 客户-助教对:")
|
||||
top_sql = """
|
||||
SELECT member_id, assistant_id, display_score, raw_score,
|
||||
session_count, attributed_recharge_amount
|
||||
FROM billiards_dws.dws_member_assistant_intimacy
|
||||
ORDER BY display_score DESC
|
||||
LIMIT 5
|
||||
"""
|
||||
top_rows = db.query(top_sql)
|
||||
for i, row in enumerate(top_rows or [], 1):
|
||||
r = dict(row)
|
||||
logger.info(" %d. 会员%s-助教%s: %.2f分 (会话%d次, 归因充值%.2f元)",
|
||||
i, r['member_id'], r['assistant_id'],
|
||||
r['display_score'] or 0, r['session_count'] or 0,
|
||||
r['attributed_recharge_amount'] or 0)
|
||||
|
||||
return result
|
||||
|
||||
finally:
|
||||
db_conn.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("=" * 60)
|
||||
print("指数算法任务测试")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
# 先检查表是否存在
|
||||
config = AppConfig.load()
|
||||
db_conn = DatabaseConnection(config.config["db"]["dsn"])
|
||||
db = DatabaseOperations(db_conn)
|
||||
|
||||
check_sql = """
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'billiards_dws'
|
||||
AND table_name IN ('dws_member_recall_index', 'dws_member_assistant_intimacy', 'cfg_index_parameters')
|
||||
"""
|
||||
tables = db.query(check_sql)
|
||||
existing_tables = [dict(r)['table_name'] for r in (tables or [])]
|
||||
|
||||
if 'cfg_index_parameters' not in existing_tables:
|
||||
print("警告: cfg_index_parameters 表不存在,请先执行 schema_dws.sql")
|
||||
print("需要执行的表:")
|
||||
print(" - cfg_index_parameters")
|
||||
print(" - dws_member_recall_index")
|
||||
print(" - dws_member_assistant_intimacy")
|
||||
print(" - dws_index_percentile_history")
|
||||
db_conn.close()
|
||||
sys.exit(1)
|
||||
|
||||
db_conn.close()
|
||||
|
||||
# 测试召回指数
|
||||
recall_result = test_recall_index()
|
||||
|
||||
# 测试亲密指数
|
||||
intimacy_result = test_intimacy_index()
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
print("测试完成")
|
||||
print("=" * 60)
|
||||
print(f"召回指数: {recall_result.get('status', 'unknown')}")
|
||||
print(f"亲密指数: {intimacy_result.get('status', 'unknown')}")
|
||||
Reference in New Issue
Block a user