Repository navigation
fix(core): 하이브리드 검색의 키워드 절반이 실제 질의에서 한 번도 매칭되지 않던 문제 - #275
Merged
Merged
Conversation
plainto_tsquery 는 토큰을 전부 AND 로 묶는다. 그런데 이 검색의 질의는 꼬리질문이면 "직전질문 + 답변", 질문 풀이면 "모드 + 직군 + 자기소개 600자"라 토큰이 10~90개다. 그 전부를 담은 청크는 존재하지 않으므로 full-text 브랜치가 항상 0건이었고, RRF 가 조용히 벡터 단독 검색으로 퇴화했다. 운영 실측: 꼬리질문 질의 47/47, 질문 풀 질의 30/30 이 0건. 구현돼 있고 테스트도 통과하지만 실제 질의 형태에서는 무효인 상태였다. tsquery 를 OR 로 결합한다. 운영과 같은 헤딩 청킹 인덱스에서 질의 47개, top_k=5 기준: MRR 0.791 → 0.885 (paired bootstrap 95% CI +0.029~+0.162, 12승/3패) Top-1 0.681 → 0.830 (CI +0.043~+0.277, 8승/1패) Recall 0.936 → 0.979 후보 풀 :cand 은 손대지 않았다 — 측정한 구성이 cand = top_k 였고, 바꾸면 측정하지 않은 것을 배포하는 셈이 된다. 회귀 테스트는 벡터만으로는 top_k 밖인 청크를 키워드로만 끌어올리게 만들어 두 절반을 구분한다. 미끼를 top_k 만큼 채우지 않으면 벡터가 어차피 전부 반환해 AND 에서도 통과한다(처음에 그렇게 써서 변별력이 없었다). 기존 헬퍼 vector(head) 는 0번 차원의 크기만 바꿔 모든 벡터가 평행이라 코사인 거리가 언제나 0이었다 — 직교 단위벡터 헬퍼 axis(dim) 를 추가했다. AND 로 되돌리면 이 테스트가 실패하는 것을 확인했다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
문제
searchHybrid는 벡터 랭킹과 full-text 랭킹을 RRF 로 융합하도록 구현돼 있습니다. 그런데 full-text 브랜치가 실제 질의에서 한 번도 매칭되지 않았습니다.plainto_tsquery는 토큰을 전부&(AND)로 묶습니다. 이 검색의 질의는직전질문 + 답변→ 토큰 13~22개모드 + 직군 + 자기소개 600자→ 토큰 9~96개이고, 그 전부를 담은 청크는 존재하지 않습니다.
운영 DB 에서 질의를 그대로 재구성해 측정했습니다:
chunk_text_tsv @@ plainto_tsquery(...)매칭즉 RRF 가 조용히 벡터 단독 검색으로 퇴화한 상태였습니다. 고장이 "결과가 없다"가 아니라 "벡터 결과와 똑같다" 로 나타나서 눈에 띄지 않았습니다.
수정
tsquery 를 OR 로 결합합니다. 어휘소 사이의 구분자만 치환하므로 어휘소 내부는 건드리지 않습니다(
&는 구분자라 어휘소가 되지 못합니다).운영과 같은 헤딩 청킹 인덱스, 질의 47개,
top_k=5:현행이 벡터 단독과 47/47 완전히 동일(승0/패0/무47)한 것이 무효의 직접 증거입니다.
paired bootstrap 95% CI (20k): MRR Δ+0.093
[+0.029, +0.162](12승/3패), Top-1 Δ+0.149[+0.043, +0.277](8승/1패), Recall Δ+0.043[+0.000, +0.106].top_k=10에서도 같은 방향입니다(MRR .797→.841, Top-1 .681→.745, Recall .979→1.000).손대지 않은 것
후보 풀
:cand(=top_k)는 그대로 뒀습니다. 측정한 구성이cand = top_k였고, 여기서 바꾸면 측정하지 않은 것을 배포하는 셈입니다. 별도로 다룰 항목입니다.경계 조건
운영 PG 에서 직접 확인했습니다 — 빈 질의·구두점만 있는 질의는 빈 tsquery 가 되어 0건(현행과 동일, 벡터 단독으로 폴백), 단일 토큰은 그대로, 본문의
&문자는 구분자라 안전합니다.테스트
DocumentEmbeddingSearchTest에 실제 PG(@PostgresRepositoryTest) 기준 2건 추가.핵심은 변별력입니다. 처음 쓴 버전은 청크가 2개뿐이라 벡터만으로도 둘 다 상위 5에 들어 AND 에서도 통과했습니다. 미끼를
top_k만큼 채워 "벡터만으로는 top_k 밖인 청크를 키워드로만 끌어올리는" 상황을 만들었습니다.또 기존 헬퍼
vector(head)는 0번 차원의 크기만 바꿔 모든 벡터가 평행이라 코사인 거리가 언제나 0이었습니다(순위가 갈리지 않음). 직교 단위벡터 헬퍼axis(dim)를 추가했습니다.plainto_tsquery로 되돌리면hybridMatchesOnAnySignificantTokenNotAllOfThem이 실패하는 것을 확인했습니다../gradlew test전체 통과.🤖 Generated with Claude Code