Commit 00673e17 authored by 375242562@qq.com's avatar 375242562@qq.com

fix: 批量/手动匹配排除同一试验已匹配患者,防止重复记录

matching_service.py:
- run_matching 改为 upsert:同一 (patient_id, trial_id) 存在记录时
  直接更新 LLM 结果,不再插入新行,彻底消除重复记录
- 仅首次匹配时向医生发送通知,重新匹配不重复推送

batch_matching_service.py:
- existing_pairs 查询从全表扫描改为按目标试验过滤,提升性能
- 只查 MatchingResult 的 patient_id/trial_id 列(select 子集)
Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 0eda58d9
import asyncio
from datetime import datetime
from sqlalchemy import select
from sqlalchemy import select, tuple_
from app.database import AsyncSessionLocal
from app.models.patient import Patient
from app.models.trial import Trial, TrialStatus
......@@ -44,12 +44,14 @@ async def run_batch_matching(job_id: str) -> None:
)
trials = trial_result.scalars().all()
# Build set of already-matched pairs to skip
existing_result = await db.execute(select(MatchingResult))
existing_pairs = {
(r.patient_id, r.trial_id)
for r in existing_result.scalars().all()
}
# Build set of already-matched pairs to skip(只查目标试验,避免全表扫描)
trial_ids = [t.id for t in trials]
existing_result = await db.execute(
select(MatchingResult.patient_id, MatchingResult.trial_id).where(
MatchingResult.trial_id.in_(trial_ids)
)
)
existing_pairs = {(row.patient_id, row.trial_id) for row in existing_result.all()}
# Build work list (skip already matched pairs)
pairs = [
......
......@@ -117,6 +117,22 @@ async def run_matching(
}
match_status = status_map.get(llm_result.get("overall_status", ""), MatchStatus.pending_review)
# Upsert: 若该患者已对该试验有匹配记录,则更新而非新增
existing_stmt = select(MatchingResult).where(
MatchingResult.patient_id == patient_id,
MatchingResult.trial_id == trial_id,
)
matching_result = (await db.execute(existing_stmt)).scalar_one_or_none()
is_new = matching_result is None
if matching_result:
matching_result.status = match_status
matching_result.overall_score = llm_result.get("overall_score", 0.0)
matching_result.criterion_details = llm_result.get("criteria_results", [])
matching_result.evidence_spans = evidence_spans
matching_result.llm_model_used = settings.llm_model
matching_result.matched_at = datetime.utcnow()
else:
matching_result = MatchingResult(
id=str(uuid.uuid4()),
patient_id=patient_id,
......@@ -130,6 +146,12 @@ async def run_matching(
db.add(matching_result)
await db.flush()
# 仅首次匹配时向医生发送通知,避免重复推送
if not is_new:
await db.commit()
await db.refresh(matching_result)
return matching_result
# Determine recipient doctors by role
user_result = await db.execute(
select(User).options(selectinload(User.roles)).where(User.is_active == True) # noqa: E712
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment