Kiwi BM25 Retriever
Author: JeongGi Park
Peer Review:
Proofread : Juni Lee
This is a part of LangChain Open Tutorial
Overview
This tutorial explores the use of kiwipiepy
for Korean morphological analysis and demonstrates its integration within the LangChain
framework.
It highlights Korean text tokenization, and the comparison of different retrievers with various setups.
Since this tutorial covers Korean morphological analysis, the output primarily contains Korean text, reflecting the language structure being analyzed. For international users, we provide English translations alongside Korean examples.
Table of Contents
References
Environment Setup
Set up the environment. You may refer to Environment Setup for more details.
[Note]
langchain-opentutorial
is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials.You can checkout the
langchain-opentutorial
for more details.
%%capture --no-stderr
%pip install langchain-opentutorial
# Install required packages
from langchain_opentutorial import package
package.install(
[
"langsmith",
"langchain-openai",
"langchain",
"python-dotenv",
"langchain-core",
"kiwipiepy",
"rank_bm25",
"langchain-community",
"faiss-cpu",
],
verbose=False,
upgrade=False,
)
# Set environment variables
from langchain_opentutorial import set_env
set_env(
{
"OPENAI_API_KEY": "",
"LANGCHAIN_API_KEY": "",
"LANGCHAIN_TRACING_V2": "true",
"LANGCHAIN_ENDPOINT": "https://api.smith.langchain.com",
"LANGCHAIN_PROJECT": "Kiwi-BM25-Retriever",
},
)
Environment variables have been set successfully.
[Note] If you are using a .env
file, proceed as follows.
from dotenv import load_dotenv
load_dotenv(override=True)
True
Korean Tokenization
Korean words are morphologically rich. A single word is often split into multiple morphemes (root, affix, suffix, etc.).
For instance, โ์๋ ํ์ธ์โ is tokenized into:
Token(form='์๋ ', tag='NNG')
Token(form='ํ', tag='XSA')
Token(form='์ธ์', tag='EF')
We utilize kiwipiepy
, which is a Python module for Kiwi, an open-source Korean morphological analyzer, to tokenize Korean text.
from kiwipiepy import Kiwi
kiwi = Kiwi()
With this, we can easily perform tokenization.
kiwi.tokenize("์๋
ํ์ธ์? ํํ์ ๋ถ์๊ธฐ ํค์์
๋๋ค")
# Translation: Hi, this is Kiwi, a morphological analyzer.
[Token(form='์๋
', tag='NNG', start=0, len=2),
Token(form='ํ', tag='XSA', start=2, len=1),
Token(form='์ธ์', tag='EF', start=3, len=2),
Token(form='?', tag='SF', start=5, len=1),
Token(form='ํํ์', tag='NNG', start=7, len=3),
Token(form='๋ถ์๊ธฐ', tag='NNG', start=11, len=3),
Token(form='ํค์', tag='NNG', start=15, len=2),
Token(form='์ด', tag='VCP', start=17, len=1),
Token(form='แธ๋๋ค', tag='EF', start=17, len=3)]
Testing with Various Sentences
To test different retrieval methods, we define a list of documents composed of similar yet distinguishable contents.
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_core.documents import Document
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Sample documents for retriever testing
docs = [
Document(
page_content="๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค."
# Translation: Financial insurance is a financial product designed for long term asset management and risk coverage.
),
Document(
page_content="๊ธ์ต์ ์ถ๋ณดํ์ ๊ท์น์ ์ธ ์ ์ถ์ ํตํด ๋ชฉ๋์ ๋ง๋ จํ ์ ์์ผ๋ฉฐ, ์๋ช
๋ณดํ ๊ธฐ๋ฅ๋ ๊ฒธ๋นํ๊ณ ์์ต๋๋ค."
# Translation: Financial savings insurance allows individuals to accumulate a lump sum through regular savings, and also offers life insurance benefits.
),
Document(
page_content="์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค."
# Translation: Savings financial insurance helps individuals gather a lump sum through savings and finance, and also provides death benefit coverage.
),
Document(
page_content="๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค."
# Translation: Financial savings livestock insurance is a special financial product designed for long term savings, which also includes provisions for livestock products.
),
Document(
page_content="๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค."
# Translation: Financial 'carpet bombing' insurance focuses on risk coverage rather than savings. It is suitable for customers willing to take on high risk.
),
Document(
page_content="๊ธ๋ณดํ์ ์ ์ถ์ฑ๊ณผ๋ฅผ ๊ทน๋ํํฉ๋๋ค. ํนํ ๋
ธํ ๋๋น ์ ์ถ์ ์ ๋ฆฌํ๊ฒ ๊ตฌ์ฑ๋์ด ์์ต๋๋ค."
# Translation: Gold insurance maximizes returns on savings. It is especially advantageous for retirement savings.
),
Document(
page_content="๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์."
# Translation: Hey, Mr. 'Financial Bo,' please refrain from harsh words and consider saving money. I'm not sure why you're in such a hurry.
),
]
# Print tokenized documents
for doc in docs:
print(" ".join([token.form for token in kiwi.tokenize(doc.page_content)]))
๊ธ์ต ๋ณดํ ์ ์ฅ๊ธฐ ์ ์ด แซ ์์ฐ ๊ด๋ฆฌ ์ ์ํ ๋๋น ๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์ ๋ แซ ๊ธ์ต ์ํ ์ด แธ๋๋ค .
๊ธ์ต ์ ์ถ ๋ณดํ ์ ๊ท์น ์ ์ด แซ ์ ์ถ ์ ํตํ ์ด ๋ชฉ๋ ์ ๋ง๋ จ ํ แฏ ์ ์ ์ผ๋ฉฐ , ์๋ช
๋ณดํ ๊ธฐ๋ฅ ๋ ๊ฒธ๋น ํ ๊ณ ์ ์ต๋๋ค .
์ ์ถ ๊ธ์ต ๋ณดํ ์ ์ ์ถ ๊ณผ ๊ธ์ต ์ ํตํ ์ด ๋ชฉ๋ ๋ง๋ จ ์ ๋์ ์ ์ฃผ ๋ ๋ณดํ ์ด แธ๋๋ค . ๋ํ , ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ ๋ ์ ๊ณต ํ แธ๋๋ค .
๊ธ์ต ์ ์ถ์ฐ๋ฌผ ๋ณดํ ์ ์ฅ๊ธฐ ์ ์ด แซ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ ์ด , ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ ์ ๊ฐ์ถ ๊ณ ์ ๋ ํน๋ณ ๊ธ์ต ์ํ ์ด แธ๋๋ค .
๊ธ์ต ๋จ ํญ๊ฒฉ ๋ณดํ ์ ์ ์ถ ์ ์ปค๋
์ํ ๋๋น ์ ์ด์ ์ ๋ง์ถ แซ ์ํ ์ด แธ๋๋ค . ๋ ์ ์ํ ์ ๊ฐ์ ํ ๊ณ ์ ํ ๋ ๊ณ ๊ฐ ์๊ฒ ์ ํฉ ํ แธ๋๋ค .
๊ธ ๋ณดํ ์ ์ ์ถ ์ฑ๊ณผ ๋ฅผ ๊ทน๋ ํ ํ แธ๋๋ค . ํนํ ๋
ธํ ๋๋น ์ ์ถ ์ ์ ๋ฆฌ ํ ๊ฒ ๊ตฌ์ฑ ๋ ์ด ์ ์ต๋๋ค .
๊ธ์ต ๋ณด ์จ ํํ แซ ๋ง ์ข ํ ์ง ๋ง ์ ๊ณ , ์ ์ถ ์ด๋ ์ข ํ ์ ๋๊ฐ์ . ๋ญ ๊ฐ ๊ทธ๋ฆฌ ๊ธํ ์ แซ์ง ๋ชจ๋ฅด ๊ฒ ๋ค์ .
# Define a tokenization function
def kiwi_tokenize(text):
return [token.form for token in kiwi.tokenize(text)]
Comparing Search Results Using Different Retrievers
In this section, we compare how different retrieval methods rank documents when given the same query. We are using:
BM25: A traditional ranking function based on term frequency (TF) and inverse document frequency (IDF).
Kiwi BM25: BM25 with an added benefit of kiwipiepy tokenization, enabling more accurate splitting of Korean words into morphemes (especially important for Korean queries).
FAISS: A vector-based retriever using embeddings (in this case,
OpenAIEmbeddings
). It captures semantic similarity, so itโs less reliant on exact keyword matches and more on meaning.Ensemble: A combination of BM25 (or Kiwi BM25) and FAISS, weighted to leverage both the lexical matching strengths of BM25 and the semantic understanding of FAISS.
Key points of Comparison
Exact Keyword Matching vs. Semantic Matching
BM25 (and Kiwi BM25) excel in finding documents that share exact terms or closely related morphological variants.
FAISS retrieves documents that may not have exact lexical overlap but are semantically similar (e.g., synonyms or paraphrases).
Impact of Korean morphological analysis
Korean often merges stems and endings into single words (โ์๋ ํ์ธ์โ โ โ์๋ + ํ + ์ธ์โ). Kiwi BM25 handles this by splitting the query and documents more precisely.
This can yield more relevant results when dealing with conjugated verbs, particles, or compound nouns.
Ensemble Approaches
By combining lexical (BM25) and semantic (FAISS) retrievers, we can produce a more balanced set of results.
The weighting (e.g., 70:30 or 30:70) can be tuned to emphasize one aspect over the other.
Using MMR (Maximal Marginal Relevance) ensures diversity in the retrieved results, reducing redundancy.
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
# Initialize BM25 retriever using raw documents
bm25 = BM25Retriever.from_documents(docs)
# Initialize BM25 retriever with a custom preprocessing function (e.g., Kiwi tokenizer)
kiwi_bm25 = BM25Retriever.from_documents(docs, preprocess_func=kiwi_tokenize)
# Initialize FAISS retriever with OpenAI embeddings
faiss = FAISS.from_documents(docs, OpenAIEmbeddings()).as_retriever()
# Create an ensemble retriever combining BM25 and FAISS with a 70:30 weighting
bm25_faiss_73 = EnsembleRetriever(
retrievers=[bm25, faiss], # List of retrieval models to combine
weights=[0.7, 0.3], # Weighting for BM25 (70%) and FAISS (30%) results
search_type="mmr", # Use MMR (Maximal Marginal Relevance) to diversify search results
)
# Create an ensemble retriever combining BM25 and FAISS with a 30:70 weighting
bm25_faiss_37 = EnsembleRetriever(
retrievers=[bm25, faiss], # List of retrieval models to combine
weights=[0.3, 0.7], # Weighting for BM25 (30%) and FAISS (70%) results
search_type="mmr", # Use MMR (Maximal Marginal Relevance) to diversify search results
)
# Create an ensemble retriever combining Kiwi BM25 and FAISS with a 70:30 weighting
kiwibm25_faiss_73 = EnsembleRetriever(
retrievers=[kiwi_bm25, faiss], # List of retrieval models to combine
weights=[0.7, 0.3], # Weighting for Kiwi BM25 (70%) and FAISS (30%) results
search_type="mmr", # Use MMR (Maximal Marginal Relevance) to diversify search results
)
# Create an ensemble retriever combining Kiwi BM25 and FAISS with a 30:70 weighting
kiwibm25_faiss_37 = EnsembleRetriever(
retrievers=[kiwi_bm25, faiss], # List of retrieval models to combine
weights=[0.3, 0.7], # Weighting for Kiwi BM25 (30%) and FAISS (70%) results
search_type="mmr", # Use MMR (Maximal Marginal Relevance) to diversify search results
)
# Dictionary to store all retrievers for easy access
retrievers = {
"bm25": bm25, # Standard BM25 retriever
"kiwi_bm25": kiwi_bm25, # BM25 retriever with Kiwi tokenizer
"faiss": faiss, # FAISS retriever with OpenAI embeddings
"bm25_faiss_73": bm25_faiss_73, # Ensemble retriever (BM25:70%, FAISS:30%)
"bm25_faiss_37": bm25_faiss_37, # Ensemble retriever (BM25:30%, FAISS:70%)
"kiwi_bm25_faiss_73": kiwibm25_faiss_73, # Ensemble retriever (Kiwi BM25:70%, FAISS:30%)
"kiwi_bm25_faiss_37": kiwibm25_faiss_37, # Ensemble retriever (Kiwi BM25:30%, FAISS:70%)
}
# Define a function to print search results from multiple retrievers
def print_search_results(retrievers, query):
"""
Prints the top search result from each retriever for a given query.
Args:
retrievers (dict): A dictionary of retriever instances.
query (str): The search query.
"""
print(f"Query: {query}")
for name, retriever in retrievers.items():
# Retrieve and print the top search result for each retriever
print(f"{name}\t: {retriever.invoke(query)[0].page_content}")
print("===" * 20)
Displaying Search Results
Let's display the search results for a variety of queries, and see how different retrievers perform.
print_search_results(retrievers, "๊ธ์ต๋ณดํ")
Query: ๊ธ์ต๋ณดํ
bm25 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
kiwi_bm25 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
faiss : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_73 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
bm25_faiss_37 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
kiwi_bm25_faiss_73 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_37 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
============================================================
print_search_results(retrievers, "๊ธ์ต ๋ณดํ")
Query: ๊ธ์ต ๋ณดํ
bm25 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
faiss : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_73 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_37 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_73 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_37 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
============================================================
print_search_results(retrievers, "๊ธ์ต์ ์ถ๋ณดํ")
Query: ๊ธ์ต์ ์ถ๋ณดํ
bm25 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
kiwi_bm25 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
faiss : ๊ธ์ต์ ์ถ๋ณดํ์ ๊ท์น์ ์ธ ์ ์ถ์ ํตํด ๋ชฉ๋์ ๋ง๋ จํ ์ ์์ผ๋ฉฐ, ์๋ช
๋ณดํ ๊ธฐ๋ฅ๋ ๊ฒธ๋นํ๊ณ ์์ต๋๋ค.
bm25_faiss_73 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
bm25_faiss_37 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_73 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
kiwi_bm25_faiss_37 : ๊ธ์ต์ ์ถ๋ณดํ์ ๊ท์น์ ์ธ ์ ์ถ์ ํตํด ๋ชฉ๋์ ๋ง๋ จํ ์ ์์ผ๋ฉฐ, ์๋ช
๋ณดํ ๊ธฐ๋ฅ๋ ๊ฒธ๋นํ๊ณ ์์ต๋๋ค.
============================================================
print_search_results(retrievers, "์ถ์ฐ๋ฌผ ๋ณดํ")
Query: ์ถ์ฐ๋ฌผ ๋ณดํ
bm25 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
faiss : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_73 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_37 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_73 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
kiwi_bm25_faiss_37 : ๊ธ์ต์ ์ถ์ฐ๋ฌผ๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์ ์ถ ๋ชฉ์ ๊ณผ ๋๋ถ์ด, ์ถ์ฐ๋ฌผ ์ ๊ณต ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์๋ ํน๋ณ ๊ธ์ต ์ํ์
๋๋ค.
============================================================
print_search_results(retrievers, "์ ์ถ๊ธ์ต๋ณดํ")
Query: ์ ์ถ๊ธ์ต๋ณดํ
bm25 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
kiwi_bm25 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
faiss : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
bm25_faiss_73 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
bm25_faiss_37 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
kiwi_bm25_faiss_73 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
kiwi_bm25_faiss_37 : ์ ์ถ๊ธ์ต๋ณดํ์ ์ ์ถ๊ณผ ๊ธ์ต์ ํตํด ๋ชฉ๋ ๋ง๋ จ์ ๋์์ ์ฃผ๋ ๋ณดํ์
๋๋ค. ๋ํ, ์ฌ๋ง ๋ณด์ฅ ๊ธฐ๋ฅ๋ ์ ๊ณตํฉ๋๋ค.
============================================================
print_search_results(retrievers, "๊ธ์ต๋ณด์จ ๊ฐ์ธ์ ๋ณด ์กฐํ")
Query: ๊ธ์ต๋ณด์จ ๊ฐ์ธ์ ๋ณด ์กฐํ
bm25 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
kiwi_bm25 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
faiss : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
bm25_faiss_73 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
bm25_faiss_37 : ๊ธ์ต๋จํญ๊ฒฉ๋ณดํ์ ์ ์ถ์ ์ปค๋
์ํ ๋๋น์ ์ด์ ์ ๋ง์ถ ์ํ์
๋๋ค. ๋์ ์ํ์ ๊ฐ์ํ๊ณ ์ ํ๋ ๊ณ ๊ฐ์๊ฒ ์ ํฉํฉ๋๋ค.
kiwi_bm25_faiss_73 : ๊ธ์ต๋ณด์จ ํํ๋ง ์ข ํ์ง๋ง์๊ณ , ์ ์ถ์ด๋ ์ข ํ์๋๊ฐ์. ๋ญ๊ฐ ๊ทธ๋ฆฌ ๊ธํ์ ์ง ๋ชจ๋ฅด๊ฒ ๋ค์.
kiwi_bm25_faiss_37 : ๊ธ์ต๋ณดํ์ ์ฅ๊ธฐ์ ์ธ ์์ฐ ๊ด๋ฆฌ์ ์ํ ๋๋น๋ฅผ ๋ชฉ์ ์ผ๋ก ๊ณ ์๋ ๊ธ์ต ์ํ์
๋๋ค.
============================================================
Conclusion
By running the code and observing the top documents returned for each query, you can see how each retriever type has its strengths:
BM25
/Kiwi BM25
: Great for precise keyword matching, beneficial for Korean morphological nuances.FAISS
: Finds semantically related documents even if the wording differs.Ensemble
: Balances both worlds, often achieving better overall coverage for a wide range of queries.
Last updated