| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- #!/usr/bin/env python3
- """补全 demand_video_expansion 表中缺失的 point_desc。
- 从 multi_demand_video_point 按 (video_id, point_type, expanded_text=point_data) 匹配;
- 查不到则保持空值。
- 用法:
- .venv/bin/python scripts/backfill_demand_video_expansion_point_desc.py
- .venv/bin/python scripts/backfill_demand_video_expansion_point_desc.py --biz-dt 20260721
- .venv/bin/python scripts/backfill_demand_video_expansion_point_desc.py --biz-dt 20260721 --dry-run
- """
- from __future__ import annotations
- import argparse
- import json
- import logging
- import sys
- from pathlib import Path
- from typing import Any
- from sqlalchemy import or_, select, update
- _ROOT = Path(__file__).resolve().parents[1]
- if str(_ROOT) not in sys.path:
- sys.path.insert(0, str(_ROOT))
- from agents.demand_video_expand_agent.tools.batch_save_demand_expansions import (
- _fill_missing_point_descs,
- )
- from supply_infra.db.models.demand_video_expansion import DemandVideoExpansion
- from supply_infra.db.session import get_session
- logger = logging.getLogger(__name__)
- _BATCH_SIZE = 500
- def _list_rows_missing_point_desc(biz_dt: str | None) -> list[dict[str, Any]]:
- stmt = select(DemandVideoExpansion).where(
- DemandVideoExpansion.is_delete == 0,
- or_(
- DemandVideoExpansion.point_desc.is_(None),
- DemandVideoExpansion.point_desc == "",
- ),
- )
- if biz_dt:
- stmt = stmt.where(DemandVideoExpansion.biz_dt == biz_dt)
- stmt = stmt.order_by(DemandVideoExpansion.id)
- with get_session() as session:
- rows = session.scalars(stmt).all()
- return [
- {
- "id": int(row.id),
- "biz_dt": str(row.biz_dt),
- "video_id": str(row.video_id),
- "point_type": str(row.point_type),
- "expanded_text": str(row.expanded_text),
- "point_desc": row.point_desc,
- }
- for row in rows
- ]
- def backfill_missing_point_descs(
- biz_dt: str | None = None,
- *,
- dry_run: bool = False,
- ) -> dict[str, Any]:
- rows = _list_rows_missing_point_desc(biz_dt)
- result: dict[str, Any] = {
- "biz_dt": biz_dt,
- "dry_run": dry_run,
- "missing_total": len(rows),
- "filled": 0,
- "still_empty": 0,
- "updated": 0,
- "samples": [],
- }
- if not rows:
- return result
- with get_session() as session:
- _fill_missing_point_descs(rows, session)
- to_update: list[dict[str, Any]] = []
- for row in rows:
- if row.get("point_desc"):
- to_update.append(row)
- result["filled"] += 1
- if len(result["samples"]) < 10:
- result["samples"].append(
- {
- "id": row["id"],
- "video_id": row["video_id"],
- "point_type": row["point_type"],
- "expanded_text": row["expanded_text"],
- "point_desc": row["point_desc"][:80]
- if len(str(row["point_desc"])) > 80
- else row["point_desc"],
- }
- )
- else:
- result["still_empty"] += 1
- if dry_run or not to_update:
- result["updated"] = 0
- return result
- with get_session() as session:
- for i in range(0, len(to_update), _BATCH_SIZE):
- batch = to_update[i : i + _BATCH_SIZE]
- for row in batch:
- session.execute(
- update(DemandVideoExpansion)
- .where(DemandVideoExpansion.id == int(row["id"]))
- .values(point_desc=row["point_desc"])
- )
- result["updated"] += len(batch)
- return result
- def main(argv: list[str] | None = None) -> int:
- parser = argparse.ArgumentParser(
- description="补全 demand_video_expansion 缺失的 point_desc",
- )
- parser.add_argument("--biz-dt", default=None, help="业务日期 YYYYMMDD,默认全表")
- parser.add_argument("--dry-run", action="store_true", help="仅统计,不写库")
- parser.add_argument("--json", action="store_true", help="以 JSON 输出结果")
- args = parser.parse_args(argv)
- logging.basicConfig(
- level=logging.INFO,
- format="%(asctime)s %(levelname)s %(name)s: %(message)s",
- )
- result = backfill_missing_point_descs(args.biz_dt, dry_run=bool(args.dry_run))
- if args.json:
- print(json.dumps(result, ensure_ascii=False, indent=2, default=str))
- else:
- print("\n=== point_desc 补全 ===")
- print(f"biz_dt={result.get('biz_dt') or '全部'}")
- print(f"dry_run={result.get('dry_run')}")
- print(f"缺失记录={result.get('missing_total')}")
- print(f"可补全={result.get('filled')}")
- print(f"仍为空={result.get('still_empty')}")
- print(f"已更新={result.get('updated')}")
- if result.get("samples"):
- print("\n示例:")
- for item in result["samples"]:
- print(
- f" id={item['id']} video={item['video_id']} "
- f"type={item['point_type']} text={item['expanded_text']!r} "
- f"desc={item['point_desc']!r}"
- )
- return 0
- if __name__ == "__main__":
- raise SystemExit(main())
|