DBMS 및 SQL 활용 #5 Vector DB 스키마 설계 #
#2025-09-02
1. 개념 #
#1 KNN vs ANN
KNN과 ANN의 공통 목적
- 질문을 하고 그 질문과 비슷한 질문이나 답변을 데이터베이스에서 찾기
구현 차이
- 모든 데이터를 하나하나 다 비교해서 가장 가까운 것을 찾는다(KNN)
- 데이터 전체를 다 비교하지 않고 인덱스를 이용해서 후보군을좁혀서 그 안에서만 비교(ANN)
- 친구가 수십만 명 있으면 모든 친구에게 질문을 던져서 과거 답변을 확인하는 대신 비슷한 취향을 가진 대표 그룹 몇 개를 빠르게 찾고 그 안에서만 가장 가까운 답을 고르는 방식.
그러면 인덱스는 비슷한취향그룹 찾는데만 쓰고 그룹 안에서는 knn인가?
- 맞음
- 스텝(툴): 후보군 좁히기(ann) -> 후보군 내부 검색(knn 등)
#
#2 DB의 목적
일반적인 db는?
- 숫자, 문자열 같은 정형화된 값을 행과 열로 저장하고 필터링과 조인을 수행해서 원하는 정보를 뽑아낸다.
원하는 정보 뽑아내기?
- 조건에 맞는 행만 걸러내기
- ex) 나이가 20세 이상인 학생만 찾기 (
SELECT * FROM 학생 WHERE 나이 >= 20;)
- ex) 나이가 20세 이상인 학생만 찾기 (
- 서로 다른 테이블을 연결해서 더 풍부한 정보 만들기
- ex2) 학생 & 수강 테이블 조인을 통해 “홍길동 학생이 수강하는 과목 목록” 같은 테이블 만들기 (
SELECT 학생.이름, 수강.과목명FROM 학생JOIN 수강 ON 학생.학번 = 수강.학번;)
- ex2) 학생 & 수강 테이블 조인을 통해 “홍길동 학생이 수강하는 과목 목록” 같은 테이블 만들기 (
#
#3 일반적인 db와 벡터 db의 차이
일반적인 DB는 정확한 값을 기준으로한다.
- 예를들면 학생 이름이 “홍길동"인 데이터를 찾고 싶다면
WHERE 이름 = '홍길동'같은 조건을 써서 완전히 일치하는 값을 찾는다. - “값이 같은지 여부"라는 불(boolean) 논리에 기반해 검색과 조인을 수행.
벡터 db는 정확한값이 아니라 “얼마나 비슷한가"라는 정도를 계산한다.
- “얼마나 비슷한가” 기준?
- 벡터 간 distance 또는 similarity
- 텍스트, 이미지, 오디오 같은 데이터는 숫자 하나로 일치 여부를 판별할 수 없기 때문에 임베딩을 통해 벡터
공간에 투영한 뒤 그 벡터가 서로 얼마나 가까운지를 측정한다.
- 예를들면 “강아지"라는 단어를 검색했을 때 정확히 “강아지"라는 텍스트만 주는 게 아니라 “개”, “강쥐”, “멍멍이” 같은 비슷한 개념을 함께 찾아줄수있다.
#
#4 메타데이터
벡터 검색만 하면
- 비슷한 벡터를 찾아줄 뿐 의미는 알려주지못함.
- 비슷한 벡터를 찾을때 모두 가져올 뿐 날짜 등 필터링은 못함.
메타데이터가 있으면
- 사용자가 입력한 텍스트와 비슷한 문서를 벡터 검색으로 찾고 그 문서의 제목·저자·링크 같은 메타데이터를 함께 보여줄수있다
- 벡터 유사도로 후보를 먼저 고른 뒤 메타데이터로 Query Filtering을 하면 사용자가 원하는 결과를 정확히 얻을 수 있다.
#
#5 동적 업데이트
-> 데이터가 계속 들어오거나 수정될때를 고려
Incremental Indexing(점진적 인덱싱)
- HNSW
- 그래프기반 인덱스 구조
- 데이터가 노드, 비슷하면 엣지가있음
- 새로운벡터가 들어오면 그벡터가 노드가 됨 즉 새로운 데이터(벡터)가 들어와도 기존 그래프(인덱스)가 유지돼서 데이터가 계속들어와도 검색 성능이 떨어지지 않으면서 반영된다.
Lazy Update(지연 업데이트)
- 새로운벡터가 들어와도 즉시 반영하지않고 일정 시간이 지나면 한꺼번에 인덱스에 반영
- 자원을효율적으로 쓸수있다.
Delete & Rebuild(삭제후 재구성)
- 시간이 지나면 쓸모없는 데이터가 쌓이기때문에 일정 시간이 지나면 불필요한 벡터는 지우고 인덱스를 재정리해서 최적화해야 검색 속도가 유지되고 공간 낭비를 막을수있다.
결론
- 평소에는 Incremental Indexing과 Lazy Update로 작은 변화들을 처리하다가 주기적으로 Delete & Rebuild를 해서 전체 구조를 최적화한다.
#
#6 Chunking(청킹)
모델은 한 번에 처리할 수 있는 길이에 제한이 있고 긴 텍스트를 그대로 벡터화하면 중요한 부분이 묻힌다.
- 그래서 청킹해서 데이터를 자른다
고정 크기 방식 (Fixed Size Chunking)
- 1,000자짜리 문서를 200자로 잘라 5개로 만들기.
- 간단하고 구현이 빠른데, 문장이 잘리거나 의미가 끊길 수 있다.
의미 기반 방식 (Semantic Chunking)
- 단순히 길이가 아니라 내용의 의미 단위 즉 문단, 주제, 혹은 문맥이 바뀌는 지점에서 나눈다. 덩어리 하나가 온전한 의미를 담고 있어 검색이나 답변 생성에서 품질이 좋아진다.
중첩 방식 (Overlapping Chunking)
- 데이터를 자를 때 앞 조각과 뒤 조각이 일부 겹치도록 하는 방식, 예를 들어 200자 단위로 자르되 다음 청크는 앞에서 50자를 다시 포함시키는데 이렇게 하면 문맥이 잘려 나가는 문제를 줄일 수 있다.
요약 기반 방식 (Summarization Chunking)
- 긴 텍스트를 직접 다루기 힘들 때, 아예 요약을 해서 작은 덩어리로 줄여서 검색할 때는 요약된 덩어리만쓰는건데 검색 속도가 빨라지고 컨텍스트 길이를 절약할 수 있지만 요약 과정에서 중요한 세부 정보가 사라질 수 있다.
계층적 방식 (Hierarchical Chunking)
- 텍스트를 먼저 큰 단위(챕터)로 나누고, 그 안에서 절, 문단 단위로 세분화한다.
- “문단 단위로 세분화”
- 1장 2장으로 나누고 1장을 1.1, 1.2절로 나누고 1.1절을 첫번재문단 두번째문단 일케 나눈다.
- 문단만 최종 결과물인게 아니고 1장 같은 큰 단위도 쓰고 1.1절 같은 중간 단위도쓰고 문단 같은 작은 단위도 쓰므로 따로따로 결과물로 저장한다.
- 1장 2장으로 나누고 1장을 1.1, 1.2절로 나누고 1.1절을 첫번재문단 두번째문단 일케 나눈다.