[OpenSearch] k-NN 벡터 검색 적용하기
OpenSearch에서 k-NN 벡터 검색 적용하기
최근 자연어 처리나 이미지 인식 등 AI 기반 검색 서비스에서는 벡터 검색이 핵심 기능이 되고 있습니다. OpenSearch는 k-NN 기능을 통해 이러한 유사도 기반 검색을 지원합니다. 이 글에서는 k-NN 벡터 인덱싱이 무엇인지부터 실제 설정, 쿼리 작성까지 쉽게 따라할 수 있도록 안내드리겠습니다.
벡터 인덱싱이란?
문장을 임베딩(embedding)하면 수백 차원의 벡터로 변환되며, 이 벡터는 문장의 의미를 수치로 표현합니다. 예를 들어,
- "오늘 날씨 좋다"
- "날이 맑고 화창하다"
이 두 문장은 단어는 다르지만 의미는 유사합니다. 벡터 공간상에서는 이 둘이 가까운 위치에 있게 됩니다. 이렇게 벡터를 기반으로 유사한 문서를 찾기 위해 벡터 인덱싱이 사용됩니다.
k-NN 알고리즘이란?
k-NN(k-Nearest Neighbor)은 주어진 벡터와 가장 가까운 k개의 벡터를 찾는 알고리즘입니다. OpenSearch는 빠른 처리를 위해 근사 최근접 탐색(ANN)을 사용합니다.
주요 용어 설명
용어 | 설명 |
k | 반환할 최근접 이웃의 개수입니다. (예: 가장 유사한 5개 문서 찾기 → k=5) |
dimension | 벡터의 차원 수입니다. 저장된 벡터와 쿼리 벡터는 동일해야 합니다. (예: 임베딩 차원이 256이면 모두 256이어야 함) |
space_type | 유사도 계산 방식: cosinesimil(코사인 유사도), l2(유클리드 거리), innerproduct(내적). |
method.name | 벡터 검색 알고리즘 이름입니다. hnsw, ivf 등 선택 가능. |
method.engine | 벡터 검색 엔진: nmslib, faiss, lucene 중 선택. |
ef_construction, m | 인덱스 생성 시 정확도와 속도에 영향을 주는 하이퍼파라미터입니다. |
ef_search, nprobes | 검색 시 정확도와 성능을 조절하는 검색 관련 하이퍼파라미터입니다. |
rescore | 후보 벡터에 대한 점수 재조정을 위한 설정입니다. on_disk 모드에서 주로 사용됩니다. |
1. 인덱스 세팅 설정 예시
PUT /my-index
{
"settings": {
"index.knn": true
}
}
index.knn이 true로 설정되지 않으면 knn_vector 타입 필드는 사용 불가합니다.
2. 벡터 필드 매핑 예시
PUT /my-index/_mapping
{
"properties": {
"vector_field": {
"type": "knn_vector",
"dimension": 256,
"method": {
"name": "hnsw",
"engine": "faiss",
"space_type": "cosinesimil",
"parameters": {
"ef_construction": 128,
"m": 16
}
}
}
}
}
! 주의 1: dimension은 색인된 벡터와 쿼리 벡터 모두 동일해야 하며, 일치하지 않으면 아래 오류가 발생합니다.
Query vector has invalid dimension: X. Dimension should be: 256
! 주의 2: knn_vector 필드는 sort, aggregation과 같은 연산에서 사용할 수 없습니다.
사용 시 다음과 같은 오류가 발생할 수 있습니다.knn vector field doesn't support this operation
3. 문서 색인 예시
POST /my-index/_doc/1
{
"vector_field": [0.05, 0.12, 0.13, ..., 0.25],
"title": "샘플 문서 1"
}
POST /my-index/_doc/2
{
"vector_field": [0.10, 0.20, 0.22, ..., 0.30],
"title": "샘플 문서 2"
}
vector_field는 float형 배열이어야 하며, dimension 길이와 일치해야 합니다.
최소 k개 이상의 문서가 색인되어 있어야 의미 있는 검색이 가능합니다.
4. k-NN 검색 쿼리 예시
POST /my-index/_search
{
"size": 2,
"query": {
"knn": {
"vector_field": {
"vector": [0.05, 0.12, ..., 0.25],
"k": 2,
"filter": { "term": { "category": "A" } },
"method_parameters": { "ef_search": 150 },
"rescore": { "oversample_factor": 1.0 }
}
}
}
}
예시: k=2, size=2로 설정하면 각 샤드에서 유사한 문서 2개를 찾고, 그 중 상위 2개의 결과만 반환합니다.
5. 발생 가능한 오류 및 해결 방법
오류 메시지 | 원인 | 해결 방법 |
Query vector has invalid dimension: X... | 쿼리 벡터와 매핑된 dimension 불일치 | 쿼리 벡터 길이 확인 및 수정 |
knn vector field doesn't support this operation | knn_vector 필드로 정렬/집계 시도 | 정렬이 필요하면 keyword 필드 분리 사용 |
unsupported_operation_exception | knn 필드를 sort 또는 DSL 기능으로 잘못 참조 | 쿼리 구조 재검토 또는 field usage 변경 |
6. 사용 예시
PUT /products
{
"settings": { "index.knn": true },
"mappings": {
"properties": {
"features": {
"type": "knn_vector",
"dimension": 4,
"method": {
"name": "ivf",
"engine": "faiss",
"space_type": "l2",
"parameters": { "nlist": 16 }
}
},
"price": { "type": "float" },
"category": { "type": "keyword" }
}
}
}
POST /products/_doc/1
{ "features": [1.0, 2.0, 3.0, 4.0], "price": 100, "category": "A" }
POST /products/_doc/2
{ "features": [1.1, 2.1, 3.1, 4.1], "price": 120, "category": "A" }
POST /products/_doc/3
{ "features": [10.0, 10.5, 11.0, 11.5], "price": 200, "category": "B" }
POST /products/_search
{
"size": 2,
"query": {
"knn": {
"features": {
"vector": [1.05, 2.05, 3.05, 4.05],
"k": 2,
"filter": { "term": { "category": "A" } }
}
}
}
}
dimension은 벡터 차원(예시에서는, dimension = 4)과 일치해야 하며, category: A 조건을 통해 A 그룹 내에서만 유사 문서를 검색합니다. 벡터가 가장 가까운 문서 1번과 2번이 반환됩니다.