CocoIndex로 시맨틱 검색 엔진을 구축한 방법
Source: Dev.to
소개
이 튜토리얼에서는 CocoIndex라는 오픈소스 파이썬 라이브러리를 사용해 의미 기반 검색 엔진을 구축하는 과정을 단계별로 안내합니다. 정확한 키워드 매치가 아니라 문맥과 의미를 이해하는 검색 기능을 만들고 싶다면 이 글이 도움이 될 것입니다!
CocoIndex란?
CocoIndex는 벡터 임베딩을 이용해 문서를 인덱싱하고 검색할 수 있게 해 주는 가벼운 의미 검색 라이브러리입니다. 기존의 키워드 기반 검색과 달리 의미 검색은 쿼리 뒤에 숨은 의미를 파악하여 사용자가 다른 단어를 사용하더라도 관련 결과를 찾아줍니다.
내가 CocoIndex를 선택한 이유
나는 다음과 같은 검색 솔루션이 필요했습니다:
- 통합이 쉬움 – 복잡한 설정이나 인프라가 필요 없음
- 빠름 – 인덱싱 및 검색 성능이 우수
- 의미 기반 – 키워드가 아니라 문맥을 이해
- 오픈소스 – 자유롭게 사용하고 수정 가능
CocoIndex는 이 모든 요구사항을 만족했습니다!
시작하기
먼저 CocoIndex를 설치합니다:
pip install cocoindex
검색 엔진 구축
1. CocoIndex 초기화
from cocoindex import CocoIndex
2. 문서 추가
@cocoindex.flow_def(name="TextEmbedding")
def text_embedding_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope):
"""
Define an example flow that embeds text into a vector database.
"""
data_scope["documents"] = flow_builder.add_source(
cocoindex.sources.LocalFile(path="markdown_files")
)
doc_embeddings = data_scope.add_collector()
문서 인덱싱
각 문서 처리
with data_scope["documents"].row() as doc:
doc["chunks"] = doc["content"].transform(
cocoindex.functions.SplitRecursively(),
language="markdown",
chunk_size=2000,
chunk_overlap=500,
)
임베딩
with doc["chunks"].row() as chunk:
chunk["embedding"] = chunk["text"].transform(
cocoindex.functions.SentenceTransformerEmbed(
model="sentence-transformers/all-MiniLM-L6-v2"
)
)
doc_embeddings.collect(
filename=doc["filename"],
location=chunk["location"],
text=chunk["text"],
embedding=chunk["embedding"],
)
내보내기
doc_embeddings.export(
"doc_embeddings",
cocoindex.storages.Postgres(),
primary_key_fields=["filename", "location"],
vector_indexes=[
cocoindex.VectorIndexDef(
field_name="embedding",
metric=cocoindex.VectorSimilarityMetric.COSINE_SIMILARITY,
)
],
)
3. 의미 검색 수행
def search(pool: ConnectionPool, query: str, top_k: int = 5):
table_name = cocoindex.utils.get_target_storage_default_name(
text_embedding_flow, "doc_embeddings"
)
query_vector = text_to_embedding.eval(query)
with pool.connection() as conn:
with conn.cursor() as cur:
cur.execute(
f"""
SELECT filename, text, embedding %s::vector AS distance
FROM {table_name}
ORDER BY distance
LIMIT %s
""",
(query_vector, top_k),
)
return [
{"filename": row[0], "text": row[1], "score": 1.0 - row[2]}
for row in cur.fetchall()
]
구현한 핵심 기능
빠른 인덱싱
CocoIndex는 효율적인 벡터 저장소를 사용해 수천 개 문서의 인덱싱을 빠르고 손쉽게 수행합니다.
의미 이해
검색은 “컴퓨터 교육”이 “머신러닝”과 연관된다는 것을 정확한 키워드 매치 없이도 파악합니다.
커스터마이징 가능한 임베딩
사용 사례와 정확도 요구에 따라 다양한 임베딩 모델을 선택해 사용할 수 있습니다.
실제 사례
내 프로젝트의 문서 검색을 500개 이상의 마크다운 파일로 구축했습니다. CocoIndex를 사용한 결과:
- 인덱싱 시간 30초 미만
- 검색 응답 시간 평균 50 ms
- 사용자는 모호한 쿼리에도 관련 문서를 찾을 수 있었습니다
성능 향상 팁
- 배치 인덱싱 – 한 번에 여러 문서를 추가하면 성능이 개선됩니다
- 적절한 임베딩 모델 선택 – 정확도와 속도 사이의 균형을 맞추세요
- 자주 조회되는 결과 캐시 – 일반적인 쿼리를 저장해 즉시 응답하도록 합니다
직면했던 과제
과제 1: 임베딩 차원 선택
차원이 높을수록 정확도는 올라가지만 속도가 느려집니다. 나는 384 차원을 최적점으로 정했습니다.
과제 2: 대용량 문서 컬렉션 처리
10 k 개 이상의 문서 컬렉션에서는 페이지네이션과 지연 로딩을 구현했습니다.
결과
CocoIndex를 도입한 뒤:
- 사용자 만족도가 크게 상승했습니다
- 구현 기간이 대안에 비해 2일에 불과했습니다 (몇 주가 걸리던 작업)
결론
CocoIndex 덕분에 의미 기반 검색 엔진을 매우 간단하게 만들 수 있었습니다. 문서 사이트, 블로그 검색, 제품 카탈로그 등 어떤 검색 기능을 구축하든 무게 대비 뛰어난 도구입니다. 라이브러리는 활발히 유지보수되고 문서도 잘 정리돼 있으며 커뮤니티도 친절합니다. 다음 검색 구현에 꼭 한 번 사용해 보시길 강력히 추천합니다!
참고 자료
- GitHub: CocoIndex Repository
- Documentation: Official Docs
- Demo Project: Simple Vector Index Demo