dedupe.py 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. """Deduplication helpers for acquisition -> decode -> ingest pipelines."""
  2. from __future__ import annotations
  3. from dataclasses import dataclass
  4. from typing import Iterable
  5. from acquisition.domain import CandidateItem
  6. @dataclass(frozen=True)
  7. class DedupeDecision:
  8. keep: bool
  9. key: str
  10. reason: str = ""
  11. def item_dedupe_key(item: CandidateItem) -> str:
  12. if item.platform_item_id:
  13. return f"{item.platform}:id:{item.platform_item_id}"
  14. if item.canonical_url:
  15. return f"url:{item.canonical_url.strip().lower()}"
  16. return f"item:{item.id}"
  17. def dedupe_candidate_items(items: Iterable[CandidateItem]) -> list[CandidateItem]:
  18. seen: set[str] = set()
  19. out: list[CandidateItem] = []
  20. for item in items:
  21. key = item_dedupe_key(item)
  22. if key in seen:
  23. continue
  24. seen.add(key)
  25. out.append(item)
  26. return out
  27. def should_decode_item(
  28. item: CandidateItem,
  29. *,
  30. decoded_item_ids: set[str] | None = None,
  31. ) -> DedupeDecision:
  32. key = item_dedupe_key(item)
  33. decoded = decoded_item_ids or set()
  34. if str(item.id) in decoded or key in decoded:
  35. return DedupeDecision(keep=False, key=key, reason="already_decoded")
  36. return DedupeDecision(keep=True, key=key)