벡터 데이터베이스 — pgvector 와 Qdrant · 벡터 검색의 원리 · 실습
pgvector 로 정확 검색까지
목표
pgvector 로 벡터를 저장하고, 세 거리 연산자의 뜻을 정규화된 벡터에서 직접 확인하고,
질의문을 벡터로 바꿔 정확 검색(exact kNN)과 범주 필터를 결합합니다. 이 실습의
결과가 다음 모듈에서 모든 근사 검색의 정답 기준이 됩니다.
왜 중요한가
벡터 검색은 "같은 낱말" 이 아니라 "가까운 뜻" 을 찾습니다. 그 일의 절반은 임베딩
모델이 하고, 나머지 절반 — 저장·거리·조건·속도 — 은 데이터베이스가 합니다.
이 실습은 뒤쪽 절반입니다. 정확 검색은 느리지만 틀리지 않으므로, 여기서 잡은
결과가 인덱스가 무엇을 놓치는지를 재는 자가 됩니다.
환경
이 파드는 postgres 계정으로 돕니다. psql 만 치면 labdb 에 붙고 vector 확장은
이미 켜져 있습니다.
export PATH=/usr/lib/postgresql/16/bin:$PATHexport PGHOST=127.0.0.1 PGUSER=lab PGDATABASE=labdbpsql픽스처는 /opt/lab/fixtures/vector/ 에 있습니다(읽기 전용으로 생각하세요).
docs.csv— 문서 2,000건 (id, category, lang, title, body). 범주 8개, 한국어·영어 혼합embeddings.csv— id 와 64차원 임베딩 문자열[0.1,0.2,...]embed.py— 질의문을 같은 64차원 공간으로 보냅니다:python3 /opt/lab/fixtures/vector/embed.py "질의문"queries.json— 질의 20개와 미리 계산한 벡터
산출물은 전부 /root/vec/ 아래에 둡니다. mkdir -p /root/vec 를 먼저 하세요.
단계
1. articles 표를 만들고 문서 2,000건을 적재합니다 — 열은 id int primary key, category text, lang text, title text, body text, embedding vector(64). 문서는 /opt/lab/fixtures/vector/docs.csv 를 COPY 로 넣습니다(임베딩은 아직 비워 둡니다).
2. /opt/lab/fixtures/vector/embeddings.csv(id, embedding) 의 벡터를 articles.embedding 에 채우고, /root/vec/02-load.txt 에 rows=·with_embedding=·dim= 세 줄을 남깁니다.
3. 문서 42 와 43 사이의 거리를 <->·<=>·<#> 로 재고, 문서 42 에 가장 가까운 5건(자기 자신 제외)을 세 연산자 각각으로 뽑아 같은 집합인지 확인해 /root/vec/03-ops.txt 에 l2=·cosine=·ip=·top5_same= 을 남깁니다.
4. 문서 100 의 벡터로 가장 가까운 10건(자기 자신 제외)을 코사인 거리 오름차순으로 뽑아 /root/vec/04-knn.txt 에 한 줄에 하나씩 id|category|lang|title|distance 로 남깁니다.
5. embed.py 로 질의 "파드가 OOMKilled 로 계속 재시작한다" 의 벡터를 만들고, 가장 가까운 5건을 /root/vec/05-query.txt 에 id|category|lang|title|distance 로 남깁니다.
6. 질의 "디스크 사용량이 90% 를 넘어 알림이 왔다" 로 category = 'storage' and lang = 'en' 인 문서 중 가장 가까운 5건을 /root/vec/06-filter.txt 에 id|category|lang|title|distance 로 남깁니다.
7. 범주마다 avg(embedding) 으로 중심 벡터를 구하고, 질의 "결제 실패 뒤 환불 요청이 들어왔다" 와의 코사인 거리를 범주 8개 전부에 대해 오름차순으로 /root/vec/07-centroid.txt 에 category|distance 로 남깁니다.
8. search_articles(q vector(64), k int) 함수를 만들어 거리 오름차순 k 건(id, category, title, distance)을 돌려주게 하고, /opt/lab/fixtures/vector/queries.json 의 질의 20개를 그 함수로 검색해 /root/vec/08-batch.csv 에 qid,rank,id 200행을 남깁니다.
참고
- 질의 벡터는
V=$(python3 /opt/lab/fixtures/vector/embed.py "…")로 받아 SQL 에'$V'로 넣습니다. 따옴표를 빠뜨리면 대괄호가 문법 오류가 됩니다. psql -X -tA -F'|' -c "…"가id|category|…형식을 그대로 만듭니다.- 채점은 파일의 id·거리를 지금 데이터베이스에서 다시 뽑아 맞춥니다. 어떤 SQL 을 썼는지는 보지 않습니다.
- 이 실습에는 인덱스가 없습니다. 인덱스가 없어야 정확 검색이고, 그 결과가 다음 모듈의 정답입니다.
단계 8개
- vector(64) 열이 있는 표
- 임베딩 적재
- 세 거리 연산자
- 정확 kNN
- 질의문으로 검색
- 범주 필터와 결합
- 범주 중심 벡터
- 검색 함수와 일괄 검색