lllin000_PaperForge/paperforge/embedding/query_rewrite.py

78 lines
3 KiB
Python
Raw Normal View History

"""Query expansion for @ Deep Search — abbreviation expansion and synonym mapping."""
from __future__ import annotations
import re
# Common orthopedic/medical abbreviations used in literature
ABBREVIATIONS: dict[str, str] = {
"ACL": "anterior cruciate ligament",
"PCL": "posterior cruciate ligament",
"MCL": "medial collateral ligament",
"LCL": "lateral collateral ligament",
"VTE": "venous thromboembolism",
"DVT": "deep vein thrombosis",
"RCT": "rotator cuff",
"OA": "osteoarthritis",
"THA": "total hip arthroplasty",
"TKA": "total knee arthroplasty",
"ROM": "range of motion",
"BMI": "body mass index",
"NSAID": "nonsteroidal anti-inflammatory drug",
"RSA": "reverse shoulder arthroplasty",
"TSA": "total shoulder arthroplasty",
"ORIF": "open reduction internal fixation",
"TFCC": "triangular fibrocartilage complex",
"CCI": "charlson comorbidity index",
"ASA": "american society of anesthesiologists",
"PROM": "patient reported outcome measure",
"PROMIS": "patient reported outcomes measurement information system",
}
MEDICAL_SYNONYMS: dict[str, list[str]] = {
"knee": ["knee joint", "genu"],
"shoulder": ["glenohumeral joint", "shoulder joint"],
"hip": ["hip joint", "acetabulofemoral joint"],
"elbow": ["elbow joint"],
"ankle": ["ankle joint", "talocrural joint"],
"wrist": ["wrist joint", "radiocarpal joint"],
"spine": ["vertebral column", "spinal column"],
"fracture": ["fracture", "break"],
"repair": ["repair", "reconstruction", "fixation"],
"replacement": ["arthroplasty", "replacement"],
"complication": ["complication", "adverse event", "comorbidity"],
"pain": ["pain", "analgesia", "pain management"],
}
def expand_query(query: str) -> list[str]:
"""Expand query by replacing known abbreviations with full forms.
Returns a list of query variants with the original query first,
followed by expanded versions (one per abbreviation expanded).
"""
variants = [query]
seen: set[str] = set()
# Try expanding all abbreviations
expanded = query
for abbr, full in ABBREVIATIONS.items():
pattern = re.compile(r"\b" + re.escape(abbr) + r"\b", re.IGNORECASE)
if pattern.search(query):
candidate = pattern.sub(full, expanded)
if candidate != expanded and candidate not in seen:
seen.add(candidate)
variants.append(candidate)
# If no abbreviation was expanded, try synonym expansion
if len(variants) == 1:
for term, synonyms in MEDICAL_SYNONYMS.items():
pattern = re.compile(r"\b" + re.escape(term) + r"\b", re.IGNORECASE)
if pattern.search(query):
for syn in synonyms:
candidate = pattern.sub(syn, query)
if candidate != query and candidate not in seen:
seen.add(candidate)
variants.append(candidate)
break # one synonym expansion is enough
return variants