fix(L1): обрезать отпечатки равномерно по тексту, а не произвольно
winnow() возвращает set, поэтому list(fp)[:LIMIT] брал случайное подмножество: у длинного документа целые куски оставались без отпечатков, и списывание именно из них не находилось. Обнаружено при разборе того, почему фрагмент статьи PMC не искался. Добавлены winnow_ordered() — отпечатки в порядке появления в тексте, и sample_evenly() — выборка каждого n-го элемента вместо первых N. Применено в add_document и store_full_text. 7 тестов на главное свойство: выборка растянута по всей длине документа, шаг ровный, порядок сохранён. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ from sqlalchemy import func, select, update
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from app.algorithms.minhash import add_to_lsh, find_similar
|
||||
from app.algorithms.winnowing import winnow
|
||||
from app.algorithms.winnowing import sample_evenly, winnow, winnow_ordered
|
||||
from app.celery_app import celery_app
|
||||
from app.config import settings
|
||||
from app.db import db_session, get_minio, refund_plagiarism_quota, update_task_status
|
||||
@@ -284,8 +284,9 @@ def add_document(doc_data: dict[str, Any], dispatch_embed: bool = True) -> dict[
|
||||
# Вычислить fingerprints
|
||||
text = doc_data.get("full_text") or doc_data.get("abstract", "") or ""
|
||||
if text:
|
||||
fp = winnow(text)
|
||||
fingerprints_to_add = list(fp)[: settings.MAX_FINGERPRINTS_PER_DOC]
|
||||
fingerprints_to_add = sample_evenly(
|
||||
winnow_ordered(text), settings.MAX_FINGERPRINTS_PER_DOC
|
||||
)
|
||||
for i, hash_val in enumerate(fingerprints_to_add):
|
||||
session.add(Fingerprint(doc_id=doc_id, hash_value=hash_val, position=i))
|
||||
|
||||
@@ -375,7 +376,7 @@ def store_full_text(doc_id: int, text: str) -> dict[str, Any]:
|
||||
content_type="text/plain; charset=utf-8",
|
||||
)
|
||||
|
||||
hashes = list(winnow(text))[: settings.MAX_FINGERPRINTS_PER_DOC]
|
||||
hashes = sample_evenly(winnow_ordered(text), settings.MAX_FINGERPRINTS_PER_DOC)
|
||||
|
||||
with db_session() as session:
|
||||
doc = session.get(Document, doc_id)
|
||||
|
||||
Reference in New Issue
Block a user