FAISSDocumentStore

FAISSDocumentStore

FAISSDocumentStore는 FAISS를 벡터 유사도 검색에 사용하는 로컬 Document Store예요. 벡터는 FAISS 인덱스에 저장하고, 문서 데이터는 메모리에 저장하며, 선택적으로 디스크에 영속화할 수 있어요.

출처: 문서

본문

FAISSDocumentStore는 별도의 외부 데이터베이스 서비스를 실행하지 않고 가벼운 설정을 원하는 로컬 개발 및 소규모·중간 규모 데이터셋에 잘 맞아요.

설치 (Installation)

FAISS 통합을 설치하세요.

pip install faiss-haystack

초기화 (Initialization)

FAISSDocumentStore 인스턴스를 만들고 임베딩된 문서를 작성해요.

from haystack import Document
from haystack.document_stores.types import DuplicatePolicy
from haystack_integrations.document_stores.faiss import FAISSDocumentStore

document_store = FAISSDocumentStore(
    index_path="my_faiss_index",  # Optional: enables persistence on disk
    index_string="Flat",
    embedding_dim=768,
)

document_store.write_documents(
    [
        Document(content="This is first", embedding=[0.1] * 768),
        Document(content="This is second", embedding=[0.2] * 768),
    ],
    policy=DuplicatePolicy.OVERWRITE,
)

print(document_store.count_documents())

# Persist index and metadata files (`.faiss` and `.json`)
document_store.save("my_faiss_index")

영속화 (Persistence)

FAISSDocumentStore를 초기화할 때 index_path를 제공하면 해당 경로에서 기존 영속 파일(.faiss와 .json)을 로드하려고 시도해요. 명시적으로 호출할 수도 있어요.

  • save(index_path): 인덱스와 메타데이터를 디스크에 써요.
  • load(index_path): 나중에 다시 로드해요.

이전에 저장한 폴더/경로에서 로드하는 예시예요.

from haystack_integrations.document_stores.faiss import FAISSDocumentStore

# This loads `my_faiss_index.faiss` and `my_faiss_index.json` if they exist
document_store = FAISSDocumentStore(index_path="my_faiss_index")

# Alternatively, initialize first and then load explicitly
another_store = FAISSDocumentStore(embedding_dim=768)
another_store.load("my_faiss_index")

지원되는 리트리버 (Supported Retrievers)

FAISSEmbeddingRetriever: 쿼리 임베딩을 기반으로 FAISSDocumentStore에서 문서를 검색해요.

macOS에서 OpenMP 런타임 충돌 해결 (Fixing OpenMP Runtime Conflicts on macOS)

증상 (Symptoms)

런타임에 다음 오류 중 하나 또는 둘 다 발생할 수 있어요.

OMP: Error #15: Initializing libomp.dylib, but found libomp.dylib already initialized.
OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program.
resource_tracker: There appear to be 1 leaked semaphore objects to clean up at shutdown

OMP_NUM_THREADS=1로 설정하면 크래시가 사라진다면, 근본 원인은 여러 OpenMP 런타임이 동시에 로드된 것이에요. 각 런타임은 자체 스레드 풀과 스레드 로컬 저장소(TLS)를 유지해요. 두 런타임이 동시에 워커 스레드를 띄우면 서로의 메모리를 손상시켜 N > 1 스레드에서 세그폴트가 발생해요.

진단 (Diagnosis)

먼저 가상 환경에 libomp.dylib 복사본이 몇 개 있는지 찾아보세요.

find /path/to/your/.venv -name "libomp.dylib" 2>/dev/null

두 개 이상 보인다면, 예:

.venv/lib/pythonX.Y/site-packages/torch/lib/libomp.dylib
.venv/lib/pythonX.Y/site-packages/sklearn/.dylibs/libomp.dylib
.venv/lib/pythonX.Y/site-packages/faiss/.dylibs/libomp.dylib

이들을 단일 런타임으로 통합해야 해요.

해결 (Fix)

해결책은 하나의 표준 libomp.dylib(torch의 것을 추천)을 선택하고, 나머지 복사본을 모두 그곳을 가리키는 심볼릭 링크로 바꾸는 거예요.

각 중복에 대해 복사본을 삭제하고 심볼릭 링크로 교체하세요.

# Delete the duplicate
rm /path/to/.venv/lib/pythonX.Y/site-packages/<package>/.dylibs/libomp.dylib

# Replace with a symlink to the canonical copy
ln -s /path/to/.venv/lib/pythonX.Y/site-packages/torch/lib/libomp.dylib \
      /path/to/.venv/lib/pythonX.Y/site-packages/<package>/.dylibs/libomp.dylib

발견된 모든 중복에 대해 반복하세요. 이 패키지들은 @loader_path 기준 참조로 libomp.dylib를 로드하기 때문에, 심볼릭 링크는 로드 시점에 단일 표준 런타임으로 투명하게 해석돼요.

검증 (Verify)

수정을 적용한 뒤, 단 하나의 고유한 libomp.dylib만 참조되는지 확인하세요.

find /path/to/your/.venv -name "*.so" | xargs otool -L 2>/dev/null | grep libomp | sort -u

모든 항목이 같은 표준 경로로 해석되어야 해요. 이제 OMP_NUM_THREADS=1 없이도 실행할 수 있을 거예요.

더 알아보기 (Learn more)