take the points back too when an upsert fails
بررسیِ collectionها بعد از ingestِ پایه نهم نشان داد Qdrant ۲۸۷ نقطه دارد ولی دیتابیس ۲۷۹ ردیف. هشت نقطهی اضافه، همه از صفحهی ۱۲۵ — همان صفحهای که دو بار تایماوت داد و بار سوم گرفت. سه مسئله سه نسخه داشتند و دو نقطه هم بیصاحب بود. علت: `upsert` با `wait=True` ممکن است نوشته باشد و فقط جوابش تایماوت شده باشد. مسیرِ جبران فقط ردیفهای DB را پس میگرفت، نه نقطهها؛ و چون هر اجرای دوباره `qdrant_point_id` تازه میسازد، هر retry یک نسخهی تکراری اضافه میکرد. اثرش در بازیابی دیده میشود نه در لاگ: top-k با سه نسخه از یک مسئله پر میشود و بقیهی متنِ مرتبط بیرون میماند — یعنی دستیار بافتِ کمتری میبیند و هیچکس هم متوجه نمیشود. حالا در صورتِ شکست، نقطهها هم پاک میشوند. اگر خودِ پاکسازی هم شکست بخورد لاگ میشود ولی خطای اصلی پوشانده نمیشود، چون صفحه باید ناتمام بماند تا اجرای بعدی دوباره سراغش برود. دادهی موجود هم تمیز شد: ۸ نقطهی بیصاحب پاک شدند و حالا ۲۷۹ = ۲۷۹. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ from .config import build_collection_name, resolve_grade_title
|
||||
from .embedding import embed_text
|
||||
from .known_collections import is_math_subject, resolve_math_chapter
|
||||
from . import pdf as pdf_service
|
||||
from .qdrant_store import ensure_collection, upsert_points
|
||||
from .qdrant_store import delete_points, ensure_collection, upsert_points
|
||||
from .textbooks import Textbook, get_textbook
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -140,7 +140,20 @@ def _persist_and_upsert(rows: list[dict], *, lesson_id, grade_id, subject,
|
||||
for c, v in zip(created, vectors)
|
||||
])
|
||||
except Exception:
|
||||
# ⚠️ نقطهها را هم پس میگیریم، نه فقط ردیفها. upsert با wait=True ممکن
|
||||
# است نوشته باشد و فقط جوابش تایماوت شده باشد؛ آنوقت پاک کردنِ صرفِ
|
||||
# ردیفها نقطهی بیصاحب جا میگذارد، و چون اجرای بعدی شناسهی تازه
|
||||
# میسازد، هر تلاشِ دوباره یک نسخهی تکراری اضافه میکند. روی صفحهی ۱۲۵
|
||||
# کتابِ نهم همین شد: سه نسخه از یک مسئله و دو نقطهی یتیم.
|
||||
point_ids = [str(c.qdrant_point_id) for c in created]
|
||||
LessonChunk.objects.filter(pk__in=[c.pk for c in created]).delete()
|
||||
try:
|
||||
delete_points(collection, point_ids)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
'rag: پاکسازیِ %d نقطهی نیمهنوشته در %r هم شکست خورد؛ '
|
||||
'ممکن است نقطهی بیصاحب بماند.', len(point_ids), collection,
|
||||
)
|
||||
logger.exception(
|
||||
'rag: upsert به collection %r شکست خورد؛ %d ردیفِ همین دسته پس گرفته شد',
|
||||
collection, len(created),
|
||||
|
||||
@@ -38,6 +38,22 @@ def upsert_points(collection: str, points: list[dict]) -> int:
|
||||
return len(structs)
|
||||
|
||||
|
||||
def delete_points(collection: str, point_ids: list[str]) -> int:
|
||||
"""
|
||||
پاککردنِ نقاط با شناسه — برای جبرانِ upsertِ نیمهکاره.
|
||||
|
||||
`wait=True` در upsert یعنی تایماوتِ کلاینت لزوماً به معنیِ ننوشتنِ Qdrant
|
||||
نیست؛ ممکن است نوشته باشد و فقط جوابش دیر رسیده باشد. در آن حالت ردیفهای
|
||||
DB پس گرفته میشوند و نقطهها بیصاحب میمانند. این تابع همان را جمع میکند.
|
||||
"""
|
||||
if not point_ids:
|
||||
return 0
|
||||
client = clients.get_qdrant_client()
|
||||
client.delete(collection_name=collection,
|
||||
points_selector=[str(i) for i in point_ids], wait=True)
|
||||
return len(point_ids)
|
||||
|
||||
|
||||
def search(collection: str, query_vector: list[float], *, lesson_filter_value=None,
|
||||
lesson_filter_key: str | None = None, limit: int = 4) -> list[dict]:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user