Skip to content

[Test] 권한 필터에 따른 벡터 검색 누락 재현과 인덱스 방식 비교 (로컬 pgvector) - #547

Merged
Gimini-3 merged 4 commits into
developfrom
test/545
Oct 17, 2026
Merged

Gimini-3 merged 4 commits into
developfrom
test/545

Conversation

@Gimini-3

Copy link
Copy Markdown
Contributor

🔍️ 작업 내용

권한이 좁은 사용자일수록 벡터 검색 결과가 빠지는지(H1·H2)를 로컬 격리 pgvector에서 재현하고, 인덱스 방식별로 비교했습니다. 운영 코드·설정·마이그레이션은 바꾸지 않았고, 시험 코드와 결과 기록만 추가합니다.

결과 문서: gimin-#545-permission-filter-vector-recall.md

✨ 상세 설명

가설 판정

가설 현재 운영 SQL HNSW를 실제로 쓰게 했을 때 판정
H1 허용 비율이 낮으면 결과가 빠진다 재현 안 됨. HNSW를 쓰지 않음(720개 질문·조합 중 0회), 결과가 Exact와 모두 같음 재현됨. 5만 청크·topK 10·허용 10%에서 최종 1.77개(30/30 질문 topK 미달), Recall 0.18 조건부
H2 topK ≥ 11이면 40개에서 막힌다 재현 안 됨. topK 20에서 80개를 모두 돌려줌 재현됨. 허용 100%·topK 20에서 정확히 40개(SQL Recall 0.48) 조건부
  • 원인 분리: 현재 운영 계획의 DB 후보 부족은 모든 조합에서 0입니다. 남는 부족분은 허용 문서 수 × 문서당 2개 상한에서 오며, 의도된 동작입니다.
  • HNSW를 쓰지 않는 이유: documents 조인 조건 두 개를 독립으로 봐 조인 결과를 9행으로 추정합니다(실제 50,008행). 그래서 btree + 해시 조인 + top-N 정렬, 즉 사실상 Exact 검색을 고릅니다.
  • 예상 밖 발견: Generic Plan 지연. plan_cache_mode=auto에서 같은 Statement를 6번째 실행할 때부터 Generic Plan으로 바뀌고, CAST(:queryVector AS vector)를 행마다 다시 파싱합니다. 5만 청크·허용 100%에서 204ms → 4,226ms입니다. (SELECT CAST(... AS vector))로 바꾸면 Generic Plan에서도 162.8ms입니다(psql 검증).

측정 조건

  • 격리 컨테이너 pgvector/pgvector:0.8.1-pg17(CI와 같은 digest), PostgreSQL 17.8 기본 설정
  • 데이터: 저장소 팀 작성 문서 251건을 운영 Parser·Chunker·BGE-M3로 처리한 실제 3,572 청크(합성 0%), 그리고 실제 Embedding 방향을 섞어 늘린 5만 청크(합성 92.9%)
  • 질문 30개(측정 전 고정) × 허용 비율 100/10/1/0.1% × topK 5/10/20 × 방식 8가지(Exact, 현재 계획 Custom/Generic, HNSW 강제 ef40·100·200, iterative relaxed·strict) = 5,760행

변경 파일

  • backend/src/test/.../search/benchmark/PermissionRecall*.java 5개
    • 측정 하네스는 기본 test에서 제외되는 vector-search-performance 태그를 쓰고, vector.search.performance.permission.phase 속성이 있을 때만 실행됩니다.
    • 단위 테스트(PermissionRecallDatasetTest)는 기본 test에서 실행됩니다.
  • docs/test-results/gimin-#545-permission-filter-vector-recall.md
  • docs/test-results/evidence/issue-545/: 질문 세트, 원시 데이터(gzip), 요약 CSV·표, 그래프 2개, psql 실행 계획, 재현 스크립트

테스트

  • ./backend/gradlew -p backend test (develop 39dbfb9 + 이번 변경, 격리 DB·Valkey): 1,508 tests, 0 failures, 0 errors, 5 skipped
  • PermissionRecallDatasetTest 7/7 통과
  • 측정 실행: 2026-10-17, 1시간 33분. 반복 측정끼리 결과가 달라진 조합은 0개

🛠️ 추후 리팩토링 및 고도화 계획

기능테스트(10/28) 이후 별도 [Fix]에서 다시 측정한 뒤 진행할 후보입니다. 이번 PR에서는 적용하지 않았습니다.

  1. 질문 Vector를 한 번만 계산하도록 SQL을 바꿔 Generic Plan 지연 제거
  2. 지금 규모에서는 현재 계획(사실상 Exact) 유지. HNSW 경로를 도입한다면 hnsw.iterative_scan = relaxed_order 필수
  3. 다음 단계: OpenSQL VM에서 pgvectorscale(StreamingDiskANN)을 같은 하네스로 비교(절차는 결과 문서 7장)

📸 스크린샷 (선택)

허용 문서 비율별 벡터 검색 최종 결과 수

허용 100%에서 SQL이 돌려준 후보 수

💬 리뷰 요구사항

  • 5만 청크 데이터의 92.9%가 합성입니다. 합성 방법(결과 문서 3.2)이 타당한지 봐 주세요. 실제 3,572 청크에서도 같은 결론이 나왔습니다.
  • enable_sort = off로 HNSW를 쓰게 한 것은 실험 장치입니다. 쿼리를 바꿔 HNSW를 쓰게 했을 때의 계획과 다를 수 있습니다.
  • Generic Plan 지연은 운영 경로에서도 일어날 수 있는 문제라, [Fix] 우선순위를 함께 정하고 싶습니다.

운영 VectorSearchQueryService·HybridSearchQueryService를 그대로 호출하고
Repository만 반환 행을 기록하는 Proxy로 감싸, SQL 후보 수와 앱 필터 뒤
최종 건수를 따로 잰다. Exact·현재 계획(Custom/Generic Plan)·HNSW 강제
(ef_search·iterative_scan) 8가지 방식을 같은 Transaction의 SET LOCAL로 바꾼다.

- 실제 문서를 운영 Parser·Chunker·Embedding 경로로 처리해 캐시
- 실제 Embedding 방향을 섞는 결정적 합성 확장과 허용 문서 선택
- vector.search.performance.permission.phase 속성이 있을 때만 실행
합성 Vector의 단위 길이·지정 유사도, 결정적 확장, 중첩되는 허용 문서 선택,
Recall·백분위 계산을 DB 없이 검증한다.
- 예제 문서 15건·설계 문서 15건으로 만든 고정 질문 30개
- results.json을 CSV·Markdown 표·SVG 그래프로 바꾸는 스크립트
- 운영 findTopK SQL로 Custom/Generic Plan·HNSW 강제 계획을 비교하는 psql 스크립트
- 현재 검색 SQL은 HNSW를 쓰지 않아(조인 9행 오추정) 권한 필터로 결과가 빠지지 않음
- HNSW를 쓰게 하면 H1·H2 재현, iterative relaxed가 대부분 회복
- Generic Plan에서 질문 Vector를 행마다 파싱해 15~21배 느려지는 문제와 해결안 검증
@Gimini-3 Gimini-3 added the 🧪 Test 테스트 label Oct 17, 2026
@Gimini-3 Gimini-3 self-assigned this Oct 17, 2026
@Gimini-3
Gimini-3 requested a review from kangcheolung October 17, 2026 09:58
@coderabbitai

coderabbitai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: DocGrid/docgrid/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5efe5a87-9ce0-46db-9b48-2278aed9de36
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🧪 Test 테스트

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test] 권한 필터에 따른 벡터 검색 누락 재현과 인덱스 방식 비교 (로컬 pgvector)

1 participant