Spaces:
Running
Running
Update reg_embedding_system_v02.py
Browse files- reg_embedding_system_v02.py +55 -42
reg_embedding_system_v02.py
CHANGED
|
@@ -454,54 +454,67 @@ def get_unique_metadata_values(
|
|
| 454 |
return []
|
| 455 |
|
| 456 |
def smart_search_vectorstore(
|
| 457 |
-
|
|
|
|
| 458 |
query,
|
| 459 |
k=5,
|
| 460 |
-
vectorstore=None,
|
| 461 |
sqlite_conn=None,
|
| 462 |
enable_detailed_search=True
|
| 463 |
):
|
| 464 |
-
"""
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
|
| 470 |
-
|
| 471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
return basic_results
|
| 473 |
|
| 474 |
-
# 2.
|
| 475 |
-
|
|
|
|
|
|
|
|
|
|
| 476 |
for doc in basic_results:
|
| 477 |
-
|
| 478 |
-
if
|
| 479 |
-
if isinstance(
|
| 480 |
-
|
| 481 |
-
elif isinstance(
|
| 482 |
-
|
| 483 |
-
|
|
|
|
| 484 |
else:
|
| 485 |
-
|
| 486 |
|
| 487 |
-
if not
|
| 488 |
-
#
|
| 489 |
return basic_results
|
| 490 |
|
| 491 |
-
counter = Counter(
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
#logger.info(f"[상위 카테고리] {most_extracted_category}")
|
| 495 |
|
| 496 |
-
# 3. 상세 검색
|
| 497 |
detailed_results = []
|
| 498 |
-
for rank, (category, count) in enumerate(
|
| 499 |
-
#
|
| 500 |
-
metadata_filter = {
|
| 501 |
|
| 502 |
try:
|
|
|
|
| 503 |
category_results = search_with_metadata_filter(
|
| 504 |
-
|
| 505 |
vectorstore=vectorstore,
|
| 506 |
query=query,
|
| 507 |
k=k,
|
|
@@ -509,30 +522,30 @@ def smart_search_vectorstore(
|
|
| 509 |
sqlite_conn=sqlite_conn
|
| 510 |
)
|
| 511 |
detailed_results.extend(category_results)
|
| 512 |
-
|
|
|
|
| 513 |
except Exception as e:
|
| 514 |
-
|
| 515 |
continue
|
| 516 |
|
| 517 |
-
# 4. 결과 병합
|
|
|
|
| 518 |
seen = set()
|
| 519 |
final_results = []
|
| 520 |
|
| 521 |
-
#
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
final_results.append(doc)
|
| 527 |
-
|
| 528 |
-
for doc in basic_results:
|
| 529 |
doc_signature = (doc.page_content, str(sorted(doc.metadata.items())))
|
|
|
|
| 530 |
if doc_signature not in seen:
|
| 531 |
seen.add(doc_signature)
|
| 532 |
final_results.append(doc)
|
| 533 |
|
|
|
|
| 534 |
final_results = final_results[:k]
|
| 535 |
-
#logger.info(f"[최종 결과] 기본 {len(basic_results)}개 + 상세 {len(detailed_results)}개 → 중복 제거 후 {len(final_results)}개 반환")
|
| 536 |
|
| 537 |
return final_results
|
| 538 |
|
|
|
|
| 454 |
return []
|
| 455 |
|
| 456 |
def smart_search_vectorstore(
|
| 457 |
+
bm25_retriever,
|
| 458 |
+
vectorstore,
|
| 459 |
query,
|
| 460 |
k=5,
|
|
|
|
| 461 |
sqlite_conn=None,
|
| 462 |
enable_detailed_search=True
|
| 463 |
):
|
| 464 |
+
"""
|
| 465 |
+
1단계: 하이브리드 검색으로 전체 맥락 파악
|
| 466 |
+
2단계: 검색된 문서들에서 주된 'regulation'(규정) 파악
|
| 467 |
+
3단계: 해당 규정으로 필터링하여 심층 검색 수행
|
| 468 |
+
"""
|
| 469 |
|
| 470 |
+
# 1. 기본 검색 (하이브리드 검색 수행)
|
| 471 |
+
# 단순 retriever.invoke가 아니라 앞서 정의한 search_vectorstore를 사용하여
|
| 472 |
+
# Vector + BM25 결과를 섞어서 가져옵니다.
|
| 473 |
+
try:
|
| 474 |
+
basic_results = search_vectorstore(bm25_retriever, vectorstore, query, k=k)
|
| 475 |
+
except Exception as e:
|
| 476 |
+
print(f"[스마트 검색 오류] 기본 검색 실패: {e}")
|
| 477 |
+
return []
|
| 478 |
+
|
| 479 |
+
# 상세 검색이 비활성화되었거나 필수 컴포넌트가 없으면 기본 결과 반환
|
| 480 |
+
if not enable_detailed_search or not sqlite_conn:
|
| 481 |
return basic_results
|
| 482 |
|
| 483 |
+
# 2. 메타데이터 빈도 분석 (타겟 키: 'regulation')
|
| 484 |
+
# DB 스키마가 변경되었으므로 regulation_part 대신 regulation을 사용합니다.
|
| 485 |
+
target_metadata_key = 'regulation'
|
| 486 |
+
extracted_values = []
|
| 487 |
+
|
| 488 |
for doc in basic_results:
|
| 489 |
+
val = doc.metadata.get(target_metadata_key)
|
| 490 |
+
if val:
|
| 491 |
+
if isinstance(val, list):
|
| 492 |
+
extracted_values.extend(val)
|
| 493 |
+
elif isinstance(val, str):
|
| 494 |
+
# DB 저장 시 ', '로 합쳐진 문자열일 수 있으므로 분리 시도
|
| 495 |
+
if ',' in val:
|
| 496 |
+
extracted_values.extend([part.strip() for part in val.split(',')])
|
| 497 |
else:
|
| 498 |
+
extracted_values.append(val)
|
| 499 |
|
| 500 |
+
if not extracted_values:
|
| 501 |
+
# 분석할 메타데이터가 없으면 기본 결과 반환
|
| 502 |
return basic_results
|
| 503 |
|
| 504 |
+
counter = Counter(extracted_values)
|
| 505 |
+
# 상위 2개의 카테고리(규정) 추출
|
| 506 |
+
most_common_categories = counter.most_common(2)
|
|
|
|
| 507 |
|
| 508 |
+
# 3. 상세 검색 (필터링 검색)
|
| 509 |
detailed_results = []
|
| 510 |
+
for rank, (category, count) in enumerate(most_common_categories, 1):
|
| 511 |
+
# 상위 카테고리에 대해 필터링 조건 생성
|
| 512 |
+
metadata_filter = {target_metadata_key: category}
|
| 513 |
|
| 514 |
try:
|
| 515 |
+
# 변경된 search_with_metadata_filter 시그니처에 맞춰 호출
|
| 516 |
category_results = search_with_metadata_filter(
|
| 517 |
+
bm25_retriever=bm25_retriever, # [변경] Ensemble 대신 BM25 전달
|
| 518 |
vectorstore=vectorstore,
|
| 519 |
query=query,
|
| 520 |
k=k,
|
|
|
|
| 522 |
sqlite_conn=sqlite_conn
|
| 523 |
)
|
| 524 |
detailed_results.extend(category_results)
|
| 525 |
+
print(f"[스마트 검색] '{category}' 집중 검색 → {len(category_results)}개 추가")
|
| 526 |
+
|
| 527 |
except Exception as e:
|
| 528 |
+
print(f"[경고] 상세 검색 실패 ({category}): {e}")
|
| 529 |
continue
|
| 530 |
|
| 531 |
+
# 4. 결과 병합 및 중복 제거
|
| 532 |
+
# (상세 검색 결과 우선 + 기본 검색 결과)
|
| 533 |
seen = set()
|
| 534 |
final_results = []
|
| 535 |
|
| 536 |
+
# 우선순위: 상세 검색 결과 -> 기본 검색 결과
|
| 537 |
+
all_candidates = detailed_results + basic_results
|
| 538 |
+
|
| 539 |
+
for doc in all_candidates:
|
| 540 |
+
# 문서 내용과 메타데이터 문자열을 조합하여 고유 키 생성
|
|
|
|
|
|
|
|
|
|
| 541 |
doc_signature = (doc.page_content, str(sorted(doc.metadata.items())))
|
| 542 |
+
|
| 543 |
if doc_signature not in seen:
|
| 544 |
seen.add(doc_signature)
|
| 545 |
final_results.append(doc)
|
| 546 |
|
| 547 |
+
# 최종적으로 k개만 반환
|
| 548 |
final_results = final_results[:k]
|
|
|
|
| 549 |
|
| 550 |
return final_results
|
| 551 |
|