Kim Seogyu
AI/ML

Faiss와 OpenSearch 벡터 검색 비교

Facebook의 Faiss와 AWS의 OpenSearch가 제공하는 벡터 검색 기술을 비교하고, 각 도구의 강점과 적합한 사용 사례를 분석합니다.

Published 2025년 12월 31일7 min read1,303 words

Faiss와 OpenSearch 벡터 검색 비교

AI/ML 시대에 임베딩 벡터를 효율적으로 저장하고 검색하는 것은 핵심 인프라가 되었습니다. 이 글에서는 가장 널리 사용되는 두 가지 솔루션인 FaissOpenSearch를 비교 분석합니다.


개요

항목FaissOpenSearch
개발사Meta (Facebook AI Research)AWS / OpenSearch Project
유형라이브러리분산 검색 엔진
언어C++ (Python/Go 바인딩)Java (REST API)
라이선스MITApache 2.0
주요 용도순수 벡터 검색벡터 + 전문 검색 통합

Faiss: 순수 벡터 검색 라이브러리

Faiss는 Meta AI Research에서 개발한 고성능 유사도 검색 라이브러리입니다. 수십억 개의 벡터를 밀리초 단위로 검색할 수 있도록 최적화되어 있습니다.

핵심 특징

  • GPU 가속: CUDA를 활용한 병렬 처리로 CPU 대비 최대 100배 이상 빠른 검색
  • 다양한 인덱스 타입: 정확도와 속도 사이의 트레이드오프를 세밀하게 조절 가능
  • 메모리 효율: Product Quantization(PQ)를 통한 벡터 압축으로 메모리 사용량 최소화
  • 인메모리 처리: 디스크 I/O 없이 RAM에서 직접 검색

주요 인덱스 타입

graph TD
    subgraph Exact["정확한 검색 (Exact)"]
        Flat["IndexFlatL2 / IndexFlatIP"]
    end
    
    subgraph Approximate["근사 검색 (Approximate)"]
        IVF["IVF (Inverted File Index)"]
        HNSW["HNSW (Hierarchical NSW)"]
        PQ["PQ (Product Quantization)"]
    end
    
    Flat --> |"100% 정확, 느림"| Use1["소규모 데이터셋"]
    IVF --> |"클러스터 기반"| Use2["대규모 데이터셋"]
    HNSW --> |"그래프 기반"| Use3["고속 검색"]
    PQ --> |"압축 벡터"| Use4["메모리 제약 환경"]

기본 사용법 (Python)

import numpy as np
import faiss

# 데이터 준비: 10만 개의 128차원 벡터
d = 128  # 차원
nb = 100000  # 데이터베이스 크기
nq = 10  # 쿼리 수

np.random.seed(1234)
xb = np.random.random((nb, d)).astype('float32')
xq = np.random.random((nq, d)).astype('float32')

# 1. Flat Index (정확한 검색)
index_flat = faiss.IndexFlatL2(d)
index_flat.add(xb)

k = 5  # 상위 5개 결과
D, I = index_flat.search(xq, k)
print(f"가장 가까운 이웃: {I[0]}")
print(f"거리: {D[0]}")

GPU 가속 검색

import faiss

# GPU 리소스 초기화
res = faiss.StandardGpuResources()

# CPU 인덱스 → GPU 인덱스 변환
index_flat = faiss.IndexFlatL2(d)
gpu_index = faiss.index_cpu_to_gpu(res, 0, index_flat)  # GPU 0번 사용

# GPU에서 검색 (동일한 API)
gpu_index.add(xb)
D, I = gpu_index.search(xq, k)

Index Factory로 복잡한 인덱스 생성

# 문자열로 인덱스 구조 정의
# "IVF100,PQ8" = 100개 클러스터 + 8바이트 PQ 압축
index = faiss.index_factory(d, "IVF100,PQ8")

# 훈련 필요
index.train(xb)
index.add(xb)

# 검색
D, I = index.search(xq, k)

OpenSearch: 통합 검색 플랫폼

OpenSearch는 Elasticsearch의 오픈소스 포크로, 전문 검색(Full-text Search)과 벡터 검색을 모두 지원하는 분산 검색 엔진입니다.

핵심 특징

  • 하이브리드 검색: 키워드 검색 + 벡터 검색을 단일 쿼리로 결합
  • 분산 아키텍처: 클러스터 기반 수평 확장
  • 다중 엔진 지원: Faiss, Lucene, NMSLIB 중 선택 가능
  • 필터링 통합: 메타데이터 기반 pre/post 필터링
  • 관리 용이성: REST API로 모든 작업 가능

지원 엔진 비교

엔진알고리즘훈련 필요특징
LuceneHNSW아니오기본 엔진, 안정적
FaissHNSW, IVFIVF만 필요고성능, 다양한 옵션
NMSLIBHNSW아니오레거시, 호환성

인덱스 생성 (Faiss 엔진 + HNSW)

PUT /embedding-index
{
  "settings": {
    "index": {
      "knn": true,
      "knn.algo_param.ef_search": 100
    }
  },
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "embedding": {
        "type": "knn_vector",
        "dimension": 768,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "faiss",
          "parameters": {
            "ef_construction": 128,
            "m": 24
          }
        }
      }
    }
  }
}

문서 색인

POST /embedding-index/_doc
{
  "title": "Introduction to Vector Search",
  "embedding": [0.12, -0.34, 0.56, ...]  // 768차원 벡터
}

k-NN 검색 쿼리

GET /embedding-index/_search
{
  "size": 10,
  "query": {
    "knn": {
      "embedding": {
        "vector": [0.11, -0.32, 0.54, ...],
        "k": 10
      }
    }
  }
}

하이브리드 검색 (키워드 + 벡터)

GET /embedding-index/_search
{
  "size": 10,
  "query": {
    "bool": {
      "must": {
        "match": { "title": "vector search" }
      },
      "should": {
        "knn": {
          "embedding": {
            "vector": [0.11, -0.32, 0.54, ...],
            "k": 50
          }
        }
      }
    }
  }
}

상세 비교

성능

시나리오FaissOpenSearch
순수 벡터 검색 (10억 벡터)⭐⭐⭐⭐⭐⭐⭐⭐
GPU 가속✅ 네이티브 지원❌ 미지원
분산 검색❌ 수동 구현 필요✅ 내장
실시간 업데이트⚠️ 인덱스 재구축 필요✅ 실시간

확장성

graph LR
    subgraph Faiss방식["Faiss (직접 구현)"]
        App1[App Server 1] --> Shard1[(Shard 1)]
        App2[App Server 2] --> Shard2[(Shard 2)]
        App3[App Server 3] --> Shard3[(Shard 3)]
        Router[Router] --> App1
        Router --> App2
        Router --> App3
    end
    
    subgraph OpenSearch방식["OpenSearch (내장)"]
        Client[Client] --> Coordinator[Coordinator Node]
        Coordinator --> Data1[Data Node 1]
        Coordinator --> Data2[Data Node 2]
        Coordinator --> Data3[Data Node 3]
    end

운영 복잡도

항목FaissOpenSearch
설치pip install클러스터 구성
모니터링직접 구현OpenSearch Dashboards
백업/복구직접 구현스냅샷 API
고가용성직접 구현레플리카 자동화

사용 사례별 권장

Faiss를 선택해야 할 때

  1. 초저지연이 필요한 경우: 밀리초 단위의 응답 시간이 중요한 실시간 추천
  2. GPU 자원이 풍부한 경우: ML 인프라에 GPU가 이미 존재
  3. 순수 벡터 검색만 필요한 경우: 키워드 검색이 불필요
  4. 커스텀 최적화가 필요한 경우: 인덱스 파라미터 세밀 조정
# Faiss 최적 사용 예: 실시간 추천 시스템
def get_recommendations(user_embedding, k=10):
    D, I = gpu_index.search(user_embedding.reshape(1, -1), k)
    return product_ids[I[0]]  # 밀리초 내 반환

OpenSearch를 선택해야 할 때

  1. 하이브리드 검색이 필요한 경우: 키워드 + 벡터 검색 통합
  2. 운영 편의성이 중요한 경우: 모니터링, 백업 등 운영 기능 필요
  3. 기존 Elasticsearch 인프라가 있는 경우: 마이그레이션 용이
  4. 실시간 데이터 업데이트가 필요한 경우: 인덱스 재구축 없이 갱신
// OpenSearch 최적 사용 예: RAG 검색 파이프라인
{
  "query": {
    "bool": {
      "filter": { "term": { "category": "technical" } },
      "must": {
        "knn": {
          "embedding": {
            "vector": [/* query embedding */],
            "k": 20
          }
        }
      }
    }
  }
}

아키텍처 패턴

패턴 1: Faiss + Redis (고성능 캐싱)

flowchart LR
    Client[Client] --> Gateway[API Gateway]
    Gateway --> Cache{Redis Cache}
    Cache -->|Hit| Client
    Cache -->|Miss| Faiss[Faiss Index<br/>GPU Server]
    Faiss --> Cache

패턴 2: OpenSearch + LLM (RAG)

flowchart LR
    User[User Query] --> Embed[Embedding Model]
    Embed --> Search[OpenSearch k-NN]
    Search --> Context[Retrieved Context]
    Context --> LLM[LLM<br/>GPT/Claude]
    LLM --> Response[Final Response]

패턴 3: Faiss 백엔드 + OpenSearch (하이브리드)

flowchart TB
    Query[Query] --> OpenSearch[OpenSearch<br/>Keyword Search]
    Query --> Faiss[Faiss<br/>Vector Search]
    OpenSearch --> Merge[Result Merger]
    Faiss --> Merge
    Merge --> Rerank[Reranker]
    Rerank --> Final[Final Results]

마이그레이션 고려사항

Faiss → OpenSearch

# Faiss 인덱스의 벡터를 OpenSearch로 마이그레이션
from opensearchpy import OpenSearch, helpers

client = OpenSearch(hosts=['https://localhost:9200'])

def migrate_vectors(faiss_index, opensearch_index):
    vectors = faiss.rev_swig_ptr(
        faiss_index.get_xb(), faiss_index.ntotal * d
    ).reshape(-1, d)
    
    actions = [
        {
            "_index": opensearch_index,
            "_id": str(i),
            "_source": {"embedding": vectors[i].tolist()}
        }
        for i in range(len(vectors))
    ]
    
    helpers.bulk(client, actions)

OpenSearch → Faiss

# OpenSearch에서 벡터 추출 후 Faiss 인덱스 생성
from opensearchpy import OpenSearch
import numpy as np
import faiss

client = OpenSearch(hosts=['https://localhost:9200'])

def export_to_faiss(opensearch_index, field_name):
    vectors = []
    query = {"query": {"match_all": {}}, "size": 1000}
    
    response = client.search(index=opensearch_index, body=query, scroll='5m')
    while response['hits']['hits']:
        for hit in response['hits']['hits']:
            vectors.append(hit['_source'][field_name])
        response = client.scroll(scroll_id=response['_scroll_id'], scroll='5m')
    
    vectors = np.array(vectors, dtype='float32')
    index = faiss.IndexFlatL2(vectors.shape[1])
    index.add(vectors)
    return index

결론

요구사항추천 솔루션
순수 벡터 검색 성능 극대화Faiss
하이브리드 검색 (키워드 + 벡터)OpenSearch
GPU 가속 필수Faiss
운영 편의성 우선OpenSearch
마이크로서비스 통합OpenSearch
ML 파이프라인 내장Faiss

두 도구는 상호 보완적인 관계입니다. OpenSearch는 내부적으로 Faiss를 엔진으로 사용할 수 있으므로, 복잡한 검색 요구사항에는 OpenSearch를, 순수 성능이 중요한 ML 파이프라인에는 Faiss를 직접 사용하는 것이 최선의 선택입니다.


References

Share

Related Articles

Comments

이 블로그는 제가 알고 있는 것들을 잊지 않기 위해 기록하는 공간입니다.
직접 작성한 글도 있고, AI의 도움을 받아 정리한 글도 있습니다.
정확하지 않은 내용이 있을 수 있으니 참고용으로 봐주세요.

© 2026 Seogyu Kim