miniCOIL 사용하기
miniCOIL 사용하기 (fastembed-fastembed-minicoil)
miniCOIL은 오픈소스 기반의 희소 신경 검색(sparse neural retrieval) 모델이에요. 마치 BM25 기반 검색기가 키워드의 '문맥적 의미'까지 이해하고 그에 따라 결과를 순위 매기는 것처럼 동작해요. 이 튜토리얼에서는 miniCOIL 기반 희소 신경 검색이 BM25 기반 어휘 검색(lexical retrieval)과 비교했을 때 어떤 차이를 보이는지 직접 확인해 볼게요.
출처: Qdrant 공식문서
miniCOIL의 점수는 BM25 공식을 기반으로 하되, 쿼리와 문서에서 매칭된 키워드 사이의 의미적 유사도로 스케일을 조정해요.
$$ \text{miniCOIL}(D,Q) = \sum_{i=1}^{N} \text{IDF}(q_i) \cdot \text{Importance}^{q_i}_{D} \cdot {\color{YellowGreen}\text{Meaning}^{q_i \times d_j}} \text{, where keyword } d_j \in D \text{ equals } q_i $$
miniCOIL 뒤에 숨은 아이디어의 자세한 설명은 “miniCOIL: on the road to Usable Sparse Neural Retrieval” 기사나 녹화된 발표 "miniCOIL: Sparse Neural Retrieval Done Right"에서 확인하실 수 있어요.
miniCOIL을 언제 써야 하나요?
검색 결과에서 정확한 키워드 매칭이 요구되고, 모든 매칭 결과가 키워드의 문맥적 의미에 따라 순위가 매겨져야 할 때 사용해요.
결과가 의미로는 비슷하지만 겹치는 키워드 없이 다르게 표현된 경우라면, dense 임베딩을 사용하거나 miniCOIL과 결합한 하이브리드 검색 설정을 쓰는 게 낫습니다.
설정 (Setup)
fastembed와 연동되는 qdrant-client를 설치해요.
pip install "qdrant-client[fastembed]"
그 다음 Qdrant 클라이언트를 초기화해요. 실험용으로는 Qdrant Cloud의 무료 클러스터를 쓰거나 Docker로 로컬 Qdrant 인스턴스를 실행할 수 있어요.
검색은 각각 다른 맥락에서 쓰인 “vector”와 “search” 키워드를 포함하는 책·기사 제목 목록을 대상으로 진행해요. 이를 통해 miniCOIL이 BM25와 달리 이 키워드들의 의미를 어떻게 포착하는지 보여줄 거예요.
데이터셋:
documents = [ "Vector Graphics in Modern Web Design" , "The Art of Search and Self-Discovery" , "Efficient Vector Search Algorithms for Large Datasets" , "Searching the Soul: A Journey Through Mindfulness" , "Vector-Based Animations for User Interface Design" , "Search Engines: A Technical and Social Overview" , "The Rise of Vector Databases in AI Systems" , "Search Patterns in Human Behavior" , "Vector Illustrations: A Guide for Creatives" , "Search and Rescue: Technologies in Emergency Response" , "Vectors in Physics: From Arrows to Equations" , "Searching for Lost Time in the Digital Age" , "Vector Spaces and Linear Transformations" , "The Endless Search for Truth in Philosophy" , "3D Modeling with Vectors in Blender" , "Search Optimization Strategies for E-commerce" , "Vector Drawing Techniques with Open-Source Tools" , "In Search of Meaning: A Psychological Perspective" , "Advanced Vector Calculus for Engineers" , "Search Interfaces: UX Principles and Case Studies" , "The Use of Vector Fields in Meteorology" , "Search and Destroy: Cybersecurity in the 21st Century" , "From Bitmap to Vector: A Designer’s Guide" , "Search Engines and the Democratization of Knowledge" , "Vector Geometry in Game Development" , "The Human Search for Connection in a Digital World" , "AI-Powered Vector Search in Recommendation Systems" , "Searchable Archives: The History of Digital Retrieval" , "Vector Control Strategies in Public Health" , "The Search for Extraterrestrial Intelligence" ]
컬렉션 만들기 (Create Collection)
제목을 저장하고 인덱싱할 컬렉션을 만들어 볼게요.
miniCOIL은 Qdrant가 키워드의 문서빈도 역수(IDF, Inverse Document Frequency)를 계산하는 기능을 고려해 설계되었기 때문에, miniCOIL 희소 벡터를 IDF modifier와 함께 설정할 필요가 있어요.
client . create_collection ( collection_name = " {minicoil_collection_name} " , sparse_vectors_config = { "minicoil" : models . SparseVectorParams ( modifier = models . Modifier . IDF #Inverse Document Frequency ) } )
이와 유사하게, BM25 기반 희소 벡터로 컬렉션을 구성해요.
client . create_collection ( collection_name = " {bm25_collection_name} " , sparse_vectors_config = { "bm25" : models . SparseVectorParams ( modifier = models . Modifier . IDF ) } )
희소 벡터로 변환해서 Qdrant에 업로드하기
이제 제목들을 miniCOIL 희소 표현으로 변환하고 설정한 컬렉션에 업서트(upsert)할 차례예요.
Qdrant와 FastEmbed의 연동 덕분에 추론(inference) 과정을 내부에서 숨길 수 있어요. 즉:
- FastEmbed가 Hugging Face에서 선택한 모델을 다운로드하고,
- FastEmbed가 내부적으로 로컬 추론을 실행하며,
- 추론된 희소 표현이 Qdrant에 업로드됩니다.
#Estimating the average length of the documents in the corpus avg_documents_length = sum ( len ( document . split ()) for document in documents ) / len ( documents ) client . upsert ( collection_name = " {minicoil_collection_name} " , points = [ models . PointStruct ( id = i , payload = { "text" : documents [ i ] }, vector = { # Sparse miniCOIL vectors "minicoil" : models . Document ( text = documents [ i ], model = "Qdrant/minicoil-v1" , options = { "avg_len" : avg_documents_length } #Average length of documents in the corpus # (a part of the BM25 formula on which miniCOIL is built) ) }, ) for i in range ( len ( documents )) ], )
마찬가지로 BM25 기반 희소 벡터도 변환·업서트해요.
#Estimating the average length of the documents in the corpus avg_documents_length = sum ( len ( document . split ()) for document in documents ) / len ( documents ) client . upsert ( collection_name = " {bm25_collection_name} " , points = [ models . PointStruct ( id = i , payload = { "text" : documents [ i ] }, vector = { # Sparse vector from BM25 "bm25" : models . Document ( text = documents [ i ], model = "Qdrant/bm25" , options = { "avg_len" : avg_documents_length } #Average length of documents in the corpus # (a part of the BM25 formula) ) }, ) for i in range ( len ( documents )) ], )
miniCOIL로 검색하기 (Retrieve with miniCOIL)
쿼리 *“Vectors in Medicine”*를 사용해 miniCOIL과 BM25 기반 검색의 차이를 시연해 볼게요.
인덱싱된 제목 중 “medicine” 키워드를 포함한 것은 없으므로 이 단어는 유사도 점수에 기여하지 않아요. 동시에 *“vector”*라는 단어는 여러 제목에 각각 한 번씩 등장하는데, BM25 기반 검색기의 관점에서는 모든 제목에서 그 역할이 거의 동일해요. 하지만 miniCOIL은 *“medicine”*이라는 맥락 안에서 “vector” 키워드의 의미를 포착해서, *“vector”*가 의학 관련 맥락에서 쓰인 문서를 매칭할 수 있어요.
BM25 기반 검색의 경우:
query = "Vectors in Medicine" client . query_points ( collection_name = " {bm25_collection_name} " , query = models . Document ( text = query , model = "Qdrant/bm25" ), using = "bm25" , limit = 1 , )
결과는 다음과 같아요:
QueryResponse ( points =[ ScoredPoint ( id = 18, version = 1, score = 0.8405092, payload ={ 'title' : 'Advanced Vector Calculus for Engineers' } , vector = None, shard_key = None, order_value = None ) ] )
반면 miniCOIL 기반 검색의 경우:
query = "Vectors in Medicine" client . query_points ( collection_name = " {minicoil_collection_name} " , query = models . Document ( text = query , model = "Qdrant/minicoil-v1" ), using = "minicoil" , limit = 1 )
다음과 같은 결과를 얻어요:
QueryResponse ( points =[ ScoredPoint ( id = 28, version = 1, score = 0.7005557, payload ={ 'title' : 'Vector Control Strategies in Public Health' } , vector = None, shard_key = None, order_value = None ) ] )
한 가지 눈여겨볼 점은, BM25는 *“Vector Calculus”*처럼 단순히 단어를 겹쳐 매칭한 결과를 꼽은 반면, miniCOIL은 “medicine” 맥락에서 쓰인 *“Vector Control Strategies in Public Health”*를 선택했다는 거예요. 키워드의 의미를 이해해서 순위를 매기는 능력이 바로 miniCOIL의 핵심 가치랍니다.
더 알아보기 (Learn more)
- IDF modifier – 희소 벡터 설정
- miniCOIL 기사 – 아이디어 상세
- hybrid search – miniCOIL과 dense 임베딩 결합