Skip to content

Approximate k NN

OpenSearch는 기본적으로 정확한 k-NN 검색을 지원하지만, 데이터 양이 많고 벡터의 차원이 높아질수록 성능 저하 문제가 발생합니다. 이 문제를 해결하기 위한 대안으로 Approximate k-NN 검색 기능이 제공된다.

Approximate k-NN 검색은 일부 정확성을 희생하는 대신, 검색 속도를 획기적으로 높이는 방식으로 수십만 개 이상의 벡터 데이터를 다룰 때 특히 유용하다.

1. Approximate k-NN이란?

  • 정확한 k-NN: 모든 벡터 간 거리 계산 → 정확하지만 느림

  • 근사 k-NN (ANN): 인덱스 구조를 최적화하여 일부 정확도를 희생하고 속도 향상

OpenSearch는 다음 라이브러리 기반 ANN 알고리즘을 활용한다.

  • NMSLIB

  • Faiss

  • Lucene

2. 벡터 인덱스 생성

먼저 벡터 인덱스를 생성할 때 index.knn 설정을 true로 지정해야 한다. 이는 벡터를 인덱싱할 때 네이티브 라이브러리 인덱스를 생성하겠다는 뜻이다.

PUT my-knn-index-1
{
  "settings": {
    "index": {
      "knn": true,
      "knn.algo_param.ef_search": 100
    }
  },
  "mappings": {
    "properties": {
      "my_vector1": {
        "type": "knn_vector",
        "dimension": 2,
        "space_type": "l2",
        "method": {
          "name": "hnsw",
          "engine": "faiss",
          "parameters": {
            "ef_construction": 128,
            "m": 24
          }
        }
      }
    }
  }
}
  • engine: faiss, nmslib, lucene 중 선택

  • space_type: 유사도 계산 방식 (예: l2, innerproduct)

  • dimension: 벡터 차원 수

3. 데이터 색인 및 검색 예시

POST _bulk
{ "index": { "_index": "my-knn-index-1", "_id": "1" } }
{ "my_vector1": [1.5, 2.5], "price": 12.2 }
...
GET my-knn-index-1/_search
{
  "size": 2,
  "query": {
    "knn": {
      "my_vector1": {
        "vector": [2.0, 3.0],
        "k": 2
      }
    }
  }
}
  • k: 유사 벡터 수

  • size: 최종 반환할 결과 수 (샤드 수에 따라 곱해짐)

Lucene, Faiss, NMSLIB 엔진별로 ksize 해석 방식에 차이가 있음

4. 모델 기반 인덱스 구성 (Training 기반)

특정 알고리즘(예: IVF, PQ 등)을 사용할 경우 인덱싱 전에 모델 학습(Train API)이 필요하다.

Step 1: 학습용 인덱스 생성 및 데이터 삽입

PUT /train-index
{
  "mappings": {
    "properties": {
      "train-field": {
        "type": "knn_vector",
        "dimension": 4
      }
    }
  }
}
POST _bulk
{ "index": { "_index": "train-index", "_id": "1" } }
{ "train-field": [1.5, 5.5, 4.5, 6.4] }
...

index.knn은 설정하지 않아야 학습 전용으로 사용할 수 있음

Step 2: Train API 호출

POST /_plugins/_knn/models/my-model/_train
{
  "training_index": "train-index",
  "training_field": "train-field",
  "dimension": 4,
  "description": "My model description",
  "method": {
    "name": "ivf",
    "engine": "faiss",
    "parameters": {
      "encoder": {
        "name": "pq",
        "parameters": {
          "code_size": 2,
          "m": 2
        }
      }
    }
  }
}

학습이 완료되면 state: created로 변경된다.

GET /_plugins/_knn/models/my-model?filter_path=state&pretty

Step 3: 모델을 사용하는 인덱스 생성

PUT /target-index
{
  "settings": {
    "index.knn": true
  },
  "mappings": {
    "properties": {
      "target-field": {
        "type": "knn_vector",
        "model_id": "my-model"
      }
    }
  }
}

이제 이 인덱스에 데이터를 삽입하면 모델 기반 인덱스가 자동으로 구성된다.

5. 고급 기능 및 주의 사항

  • ANN 방식은 정확도보다 속도와 확장성에 중점

  • 필터 조건은 검색 후 결과에 적용됨 (사전 필터링 불가)

  • 벡터는 최대 16,000차원까지 지원

  • 벡터 인덱스는 네이티브 메모리에 로딩되며 Warmup API로 사전 로딩 가능

  • 검색 성능을 확인하려면 Stats API 활용

마무리

OpenSearch의 Approximate k-NN 검색 기능은 대용량 벡터 데이터를 빠르게 검색해야 하는 모든 상황에서 핵심 도구이다. 특히 수십만 개 이상의 고차원 벡터 데이터를 다루는 추천 시스템, 문서 유사도 검색, 이미지 검색 등에서 탁월한 성능을 발휘한다.