From b2949d26ffc5916f44266eb1ccc7c4d8748ce493 Mon Sep 17 00:00:00 2001 From: hyungi Date: Sun, 14 Jun 2026 23:18:36 +0000 Subject: [PATCH] =?UTF-8?q?fix(search):=20documents.embedding=20HNSW=20?= =?UTF-8?q?=EC=9D=B8=EB=8D=B1=EC=8A=A4(=EB=A7=88=EC=9D=B4=EA=B7=B8=20358)?= =?UTF-8?q?=20+=20ef=5Fsearch=3D100=20=E2=80=94=20docs=20vector=20leg=20se?= =?UTF-8?q?q=20scan=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit documents.embedding 에 벡터 인덱스가 없어 검색마다 40k row Parallel Seq Scan (콜드 448ms, 코퍼스 성장에 선형 악화)이었음. study_questions 와 동일 패턴의 HNSW 부분 인덱스 추가 → docs vector leg 448ms → 7.9ms (EXPLAIN Index Scan 확인). docs vector leg LIMIT=limit*4(기본 80)이라 HNSW recall 위해 ef_search>=80 필요 → ivfflat.probes 와 동일하게 ALTER DATABASE pkm SET hnsw.ef_search=100. PROD 적용: CREATE INDEX CONCURRENTLY 로 수동 빌드(무중단, /dev/shm 회피 위해 max_parallel_maintenance_workers=0 단일 스레드, 316MB) + schema_migrations(358) 수동 기록. runner 는 단일 트랜잭션이라 CONCURRENTLY 불가 → 본 파일은 fresh-init 재현용 non-concurrent IF NOT EXISTS. 검증(snapshot freeze 43958/195671, eval both, exact vs HNSW): - graded NDCG 0.575 → 0.575 (±0.000, 전 카테고리·Recall byte-identical) - ef_search=100 이 top-80 에 사실상 exact recall → 랭킹 손실 0 - prod smoke 'pressure vessel design code ASME' 작업전 5263ms → 650ms Co-Authored-By: Claude Fable 5 --- migrations/358_documents_embedding_hnsw.sql | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 migrations/358_documents_embedding_hnsw.sql diff --git a/migrations/358_documents_embedding_hnsw.sql b/migrations/358_documents_embedding_hnsw.sql new file mode 100644 index 0000000..5fc2016 --- /dev/null +++ b/migrations/358_documents_embedding_hnsw.sql @@ -0,0 +1,11 @@ +-- 358: documents.embedding HNSW 벡터 인덱스 + hnsw.ef_search (검색 latency T3, 2026-06-15) +-- PROD 적용 = CREATE INDEX CONCURRENTLY 로 수동 빌드(40k rows 무중단, /dev/shm 회피 위해 단일 스레드) +-- + schema_migrations(358) 수동 기록 완료. runner 는 단일 트랜잭션이라 CONCURRENTLY 불가. +-- 본 파일 = fresh-init/재현용: non-concurrent IF NOT EXISTS (빈 테이블 init 시 즉시, 기존 index 존재 시 no-op). +CREATE INDEX IF NOT EXISTS idx_documents_embedding_hnsw + ON documents USING hnsw (embedding vector_cosine_ops) + WHERE (deleted_at IS NULL AND embedding IS NOT NULL); + +-- docs vector leg LIMIT = limit*4 (기본 80) → HNSW recall 위해 ef_search >= 80 필요. +-- ivfflat.probes=20 과 동일하게 DB 레벨 GUC (ALTER DATABASE) 로 설정. +ALTER DATABASE pkm SET hnsw.ef_search = 100;