fix: 补充 Alembic 迁移 + bzzoiro 批量优化 + validation 兼容层

- 新增 0004_snapshot_and_constraints.py: 重命名 confidence → subjective_confidence,
  新增 cutoff_at/input_hash, 添加 CHECK 约束
- bzzoiro.py: 预加载完整 Match 对象到内存,更新路径不再重复查询
- validation.py: 旧字段 confidence 兼容并打 deprecation 日志
This commit is contained in:
shangfangjian
2026-09-15 01:42:52 +08:00
parent 2c205c68b1
commit 98e3d07cf5
3 changed files with 70 additions and 25 deletions
+10 -24
View File
@@ -151,7 +151,7 @@ class BzzoiroSource:
# === 批量优化: 预加载球队和已有比赛到内存 ===
team_name_to_id: dict[str, int] = {}
existing_match_keys: set[tuple[int, int, str]] = set()
existing_matches: dict[tuple[int, int, str], Match] = {} # 完整对象,避免重复查询
normalized_matches: list = [] # 缓存规范化结果,避免重复调用
if raw_events:
@@ -175,15 +175,11 @@ class BzzoiroSource:
teams = (await db.execute(stmt)).scalars().all()
team_name_to_id = {t.name: t.id for t in teams}
# 预加载已有比赛
from sqlalchemy import func
stmt = (
select(Match.home_team_id, Match.away_team_id, func.date(Match.match_date).label("d"))
.where(Match.league_id == league.id)
)
rows = (await db.execute(stmt)).all()
for row in rows:
existing_match_keys.add((row.home_team_id, row.away_team_id, str(row.d)))
# 预加载已有比赛(完整对象)
stmt = select(Match).where(Match.league_id == league.id)
for m in (await db.execute(stmt)).scalars():
key = (m.home_team_id, m.away_team_id, str(m.match_date_date))
existing_matches[key] = m
for nm in normalized_matches:
# 球队: 内存查找 + 按需创建
@@ -206,9 +202,9 @@ class BzzoiroSource:
# 查找已有比赛: 内存查找
date_key = nm.date.date().isoformat() if hasattr(nm.date, "date") else str(nm.date)
match_key = (home_team_id, away_team_id, date_key)
existing = None if match_key not in existing_match_keys else "exists"
existing_match = existing_matches.get(match_key)
if existing is None:
if existing_match is None:
m = Match(
league_id=league.id,
season=nm.season_label or None,
@@ -225,7 +221,7 @@ class BzzoiroSource:
)
db.add(m)
await db.flush()
existing_match_keys.add(match_key) # 防止同批重复
existing_matches[match_key] = m # 防止同批重复
if nm.home_xg is not None or nm.away_xg is not None:
stats = MatchStats(
match_id=m.id,
@@ -246,17 +242,7 @@ class BzzoiroSource:
db.add(stats)
league_r["inserted"] += 1
else:
# 已有比赛: 需要查询对象更新
from sqlalchemy import func
stmt = (
select(Match)
.where(Match.league_id == league.id)
.where(Match.home_team_id == home_team_id)
.where(Match.away_team_id == away_team_id)
.where(func.date(Match.match_date) == date_key)
)
existing_match = (await db.execute(stmt)).scalar_one()
# 已有比赛: 直接从内存获取对象更新(无需再查询)
changed = False
if existing_match.match_status != nm.match_status and nm.match_status == "finished":
existing_match.match_status = nm.match_status