Some checks are pending
Backend tests / test (push) Waiting to run
find_movie_candidates bral dowolne 50 wierszy z sumy trigramu i bloku studio+rok. Duze studio ma kilkaset filmow w trzech latach, wiec wierny duplikat wypadal z puli i powstawal nowy film. Teraz kolejnosc po similarity(). Skrypt remerge dostal tryb --same-title-studio (scalono 930 par o tym samym tytule i studiu). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
2.5 KiB
Python
66 lines
2.5 KiB
Python
"""Wyszukiwanie kandydatów do dedup movies, blocking + fuzzy title prefilter.
|
|
|
|
Strategia: nie chcemy O(N) score'ować wszystkich filmów dla każdego nowego.
|
|
Blocking: kandydat musi mieć title trigram similarity ≥0.4 (pg_trgm) z incoming title,
|
|
ALBO (same studio AND year w oknie ±1). Plus pierwsze X (np. 50) filmów z każdego
|
|
zbioru, wystarczająco szeroko żeby nie zgubić matchów, dostatecznie wąsko żeby
|
|
score'ować szybko.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import date
|
|
|
|
from sqlalchemy import or_, select
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.movie import Movie
|
|
|
|
|
|
def find_movie_candidates(
|
|
session: Session,
|
|
*,
|
|
title_normalized: str,
|
|
studio_id: uuid.UUID | None,
|
|
release_year: int | None,
|
|
limit: int = 50,
|
|
) -> list[Movie]:
|
|
"""Zwraca kandydatów do score'owania.
|
|
|
|
Trigram threshold: pg_trgm `%` operator domyślnie ma similarity ≥0.3, zniżamy
|
|
do 0.4 dla jakości. Plus secondary blocking po (studio_id, year ±1) jako safety
|
|
net dla SEO tytułów (np. mangoporn często ma "Watch Cece adult..." vs paradisehill
|
|
"Cece", trigram złapie, ale gdyby nie, studio+year wystarczają).
|
|
"""
|
|
from sqlalchemy import func, literal
|
|
|
|
# Kolejnosc po podobienstwie tytulu: bez niej LIMIT bral dowolne 50 z sumy trigramu i
|
|
# bloku studio+rok, a duze studio ma kilkaset filmow w trzech latach. Wtedy wierny
|
|
# duplikat (ten sam tytul, rok, studio i obsada) wypadal z puli i powstawal nowy film
|
|
# (2026-10-16: 13 z 228 nowych filmow z pandamovies, po scaleniu blizniaczych studiow
|
|
# bloki urosly).
|
|
q = session.execute(
|
|
select(Movie)
|
|
.where(
|
|
or_(
|
|
# pg_trgm `%`, wymagamy minimum bound 0.4 (set per-session pewnie low default).
|
|
# Bezpieczniej użyć similarity() funkcji bezpośrednio z literalnym threshold.
|
|
Movie.title_normalized.op("%")(literal(title_normalized)),
|
|
# Studio + year ±1 jako fallback blocking
|
|
_studio_year_block(studio_id, release_year),
|
|
)
|
|
)
|
|
.order_by(func.similarity(Movie.title_normalized, literal(title_normalized)).desc())
|
|
.limit(limit)
|
|
).scalars()
|
|
return list(q)
|
|
|
|
|
|
def _studio_year_block(studio_id: uuid.UUID | None, release_year: int | None):
|
|
from sqlalchemy import and_, false
|
|
if studio_id is None or release_year is None:
|
|
return false()
|
|
return and_(
|
|
Movie.studio_id == studio_id,
|
|
Movie.release_year.between(release_year - 1, release_year + 1),
|
|
)
|