pg_weight_score_builder.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. """Build local weight-score JSON files from PG Pattern V2 facts."""
  2. from __future__ import annotations
  3. import json
  4. from pathlib import Path
  5. from typing import Any
  6. from examples.demand.pg_pattern_repository import PG_PATTERN_SOURCE_SYSTEM, query_weight_score_rows
  7. DIMENSIONS = ("实质", "形式", "意图")
  8. LEVELS = ("元素", "分类")
  9. def _score(post_count: Any, occurrence_count: Any) -> float:
  10. """Stable MVP score from real PG coverage counts."""
  11. return float(post_count or 0) + float(occurrence_count or 0) / 1000000.0
  12. def _normalize_element_row(row: dict[str, Any]) -> dict[str, Any]:
  13. occurrence_count = int(row.get("occurrence_count") or 0)
  14. post_count = int(row.get("post_count") or 0)
  15. return {
  16. "name": row.get("name"),
  17. "element_type": row.get("element_type"),
  18. "category_id": row.get("category_id"),
  19. "category_path": row.get("category_path"),
  20. "occurrence_count": occurrence_count,
  21. "post_count": post_count,
  22. "score": _score(post_count, occurrence_count),
  23. "source_system": PG_PATTERN_SOURCE_SYSTEM,
  24. }
  25. def _normalize_category_row(row: dict[str, Any]) -> dict[str, Any]:
  26. occurrence_count = int(row.get("occurrence_count") or 0)
  27. post_count = int(row.get("post_count") or 0)
  28. return {
  29. "category": row.get("category"),
  30. "category_id": row.get("category_id"),
  31. "category_path": row.get("category_path"),
  32. "element_type": row.get("element_type"),
  33. "level": row.get("level"),
  34. "occurrence_count": occurrence_count,
  35. "post_count": post_count,
  36. "score": _score(post_count, occurrence_count),
  37. "source_system": PG_PATTERN_SOURCE_SYSTEM,
  38. }
  39. def build_pg_weight_score_files(
  40. execution_id: int,
  41. *,
  42. base_dir: str | Path,
  43. limit_per_file: int = 5000,
  44. ) -> dict[str, int]:
  45. """Write old-shape weight JSON files under `{base_dir}/{execution_id}`."""
  46. output_dir = Path(base_dir) / str(execution_id)
  47. output_dir.mkdir(parents=True, exist_ok=True)
  48. counts: dict[str, int] = {}
  49. for dimension in DIMENSIONS:
  50. for level in LEVELS:
  51. rows = query_weight_score_rows(
  52. execution_id=execution_id,
  53. level=level,
  54. dimension=dimension,
  55. limit=limit_per_file,
  56. )
  57. if level == "元素":
  58. payload = [_normalize_element_row(dict(row)) for row in rows]
  59. else:
  60. payload = [_normalize_category_row(dict(row)) for row in rows]
  61. payload.sort(key=lambda item: float(item.get("score") or 0), reverse=True)
  62. path = output_dir / f"{dimension}_{level}.json"
  63. path.write_text(
  64. json.dumps(payload, ensure_ascii=False, indent=2, default=str) + "\n",
  65. encoding="utf-8",
  66. )
  67. counts[f"{dimension}_{level}"] = len(payload)
  68. return counts