diff --git a/10-Retriever/10-Kiwi-BM25-Retriever.ipynb b/10-Retriever/10-Kiwi-BM25-Retriever.ipynb new file mode 100644 index 000000000..bc0be9e12 --- /dev/null +++ b/10-Retriever/10-Kiwi-BM25-Retriever.ipynb @@ -0,0 +1,671 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Kiwi BM25 Retriever\n", + "\n", + "- Author: [JeongGi Park](https://github.com/jeongkpa)\n", + "- Design: []()\n", + "- Peer Review: \n", + "- This is a part of [LangChain Open Tutorial](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial)\n", + "\n", + "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/01-Basic/07-LCEL-Interface.ipynb) [![Open in GitHub](https://img.shields.io/badge/Open%20in%20GitHub-181717?style=flat-square&logo=github&logoColor=white)](https://github.com/LangChain-OpenTutorial/LangChain-OpenTutorial/blob/main/01-Basic/07-LCEL-Interface.ipynb)\n", + "\n", + "## Overview\n", + "This document explores the use of `kiwipiepy` for Korean morphological analysis and demonstrates its integration within the `LangChain` framework. \n", + "It highlights methods to tokenize text, compare retrieval models like `BM25` and `FAISS`, and analyze relationships between queries and documents using metrics such as cosine similarity. \n", + "Additionally, it emphasizes the role of these techniques in enhancing workflows like text analysis and information retrieval.\n", + "\n", + "Since this tutorial covers Korean morphological analysis, the output primarily contains Korean text, reflecting the language structure being analyzed\n", + "For international users, we provide English translations alongside Korean examples in this tutorial.\n", + "\n", + "\n", + "### Table of Contents\n", + "\n", + "- [Overview](#overview)\n", + "- [Environment Setup](#environment-setup)\n", + "- [Korean Word Retriever Tuning](#Korean-Word-Retriever-Tuning)\n", + "- [Testing with Various Sentences](#Testing-with-Various-Sentences)\n", + "- [Experiment: Compare Search Results Using Different Retrievers](#Experiment-Compare-Search-Results-Using-Different-Retrievers)\n", + "- [Conclusion](#conclusion)\n", + "\n", + "### References\n", + "- [kiwipiepy](https://github.com/bab2min/kiwipiepy)\n", + "- [fiass](https://python.langchain.com/docs/integrations/vectorstores/faiss/)\n", + "- [openai-embeddings](https://python.langchain.com/docs/integrations/text_embedding/openai/)\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Environment Setup\n", + "\n", + "Set up the environment. You may refer to [Environment Setup](https://wikidocs.net/257836) for more details.\n", + "\n", + "**[Note]**\n", + "- `langchain-opentutorial` is a package that provides a set of easy-to-use environment setup, useful functions and utilities for tutorials. \n", + "- You can checkout the [`langchain-opentutorial`](https://github.com/LangChain-OpenTutorial/langchain-opentutorial-pypi) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install langchain-opentutorial" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# Install required packages\n", + "from langchain_opentutorial import package\n", + "\n", + "package.install(\n", + " [\n", + " \"langsmith\",\n", + " \"langchain-openai\",\n", + " \"langchain\",\n", + " \"python-dotenv\",\n", + " \"langchain-core\",\n", + " \"kiwipiepy\",\n", + " \"rank_bm25\", \n", + " \"langchain-community\",\n", + " \"faiss-cpu\",\n", + "\n", + " ],\n", + " verbose=False,\n", + " upgrade=False,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Environment variables have been set successfully.\n" + ] + } + ], + "source": [ + "# Set environment variables\n", + "from langchain_opentutorial import set_env\n", + "\n", + "set_env(\n", + " {\n", + " \"OPENAI_API_KEY\": \"\",\n", + " \"LANGCHAIN_API_KEY\": \"\",\n", + " \"LANGCHAIN_TRACING_V2\": \"true\",\n", + " \"LANGCHAIN_ENDPOINT\": \"https://api.smith.langchain.com\",\n", + " \"LANGCHAIN_PROJECT\": \"Kiwi-BM25-Retriever\",\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[Note] If you are using a `.env` file, proceed as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv(override=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Why Korean Tokenization?\n", + "\n", + "- In Korean, words are morphologically rich. For instance, “안녕하세요” is tokenized into:\n", + " - Token(form='안녕', tag='NNG')\n", + " - Token(form='하', tag='XSA')\n", + " - Token(form='세요', tag='EF')\n", + "\n", + "- Compared to English tokenization at the word level (e.g., “Hello” remains one word), Korean often splits into multiple morphemes (어근, 접사, 어미 등).\n", + "- Kiwi provides detailed POS tagging such as NNG(일반 명사), XSA(형용사 파생 접사), EF(종결 어미) to reflect these language-specific nuances.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Korean Word Retriever Tuning\n", + "\n", + "Install the Korean morphological analyzer library, `kiwipiepy`.\n", + "\n", + "[Project Link for kiwipiepy](https://github.com/bab2min/kiwipiepy)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from kiwipiepy import Kiwi\n", + "\n", + "kiwi = Kiwi()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perform Tokenization" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Token(form='안녕', tag='NNG', start=0, len=2),\n", + " Token(form='하', tag='XSA', start=2, len=1),\n", + " Token(form='세요', tag='EF', start=3, len=2),\n", + " Token(form='?', tag='SF', start=5, len=1),\n", + " Token(form='형태소', tag='NNG', start=7, len=3),\n", + " Token(form='분석기', tag='NNG', start=11, len=3),\n", + " Token(form='키위', tag='NNG', start=15, len=2),\n", + " Token(form='이', tag='VCP', start=17, len=1),\n", + " Token(form='ᆸ니다', tag='EF', start=17, len=3)]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kiwi.tokenize(\"안녕하세요? 형태소 분석기 키위입니다\")\n", + "# \"안녕하세요? 형태소 분석기 키위입니다.\" it means \"Hi, this is Kiwi, the morphological analyser.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing with Various Sentences\n", + "\n", + "BM25 is a traditional ranking function based on term frequency and inverse document frequency. It works well when exact keyword matches are important.\n", + "\n", + "\n", + "FAISS uses vector embeddings to capture semantic similarity. By combining BM25 with FAISS in an ensemble, we can leverage the lexical match benefits from BM25 and the semantic understanding from FAISS." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.retrievers import EnsembleRetriever\n", + "from langchain_community.retrievers import BM25Retriever\n", + "from langchain_core.documents import Document\n", + "from langchain_community.vectorstores import FAISS\n", + "from langchain_openai import OpenAIEmbeddings\n", + "\n", + "# Sample documents for retriever testing\n", + "docs = [\n", + " Document(\n", + " page_content=\"금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"금융저축보험은 규칙적인 저축을 통해 목돈을 마련할 수 있으며, 생명보험 기능도 겸비하고 있습니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"금보험은 저축성과를 극대화합니다. 특히 노후 대비 저축에 유리하게 구성되어 있습니다.\"\n", + " ),\n", + " Document(\n", + " page_content=\"금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\"\n", + " ),\n", + "]\n", + "\n", + "# 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "# Financial insurance is a financial product designed for long term asset management and risk coverage.\n", + "\n", + "# 금융저축보험은 규칙적인 저축을 통해 목돈을 마련할 수 있으며, 생명보험 기능도 겸비하고 있습니다.\n", + "# Financial savings insurance allows individuals to accumulate a lump sum through regular savings, and also offers life insurance benefits.\n", + "\n", + "# 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "# Savings financial insurance helps individuals gather a lump sum through savings and finance, and also provides death benefit coverage.\n", + "\n", + "# 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "# Financial savings livestock insurance is a special financial product designed for long term savings, which also includes provisions for livestock products.\n", + "\n", + "# 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "# Financial 'carpet bombing' insurance focuses on risk coverage rather than savings. It is suitable for customers willing to take on high risk.\n", + "\n", + "# 금보험은 저축성과를 극대화합니다. 특히 노후 대비 저축에 유리하게 구성되어 있습니다.\n", + "# Gold insurance maximizes returns on savings. It is especially advantageous for retirement savings.\n", + "\n", + "# 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "# Hey, Mr. 'Financial Bo,' please refrain from harsh words and consider saving money. I'm not sure why you're in such a hurry.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "금융 보험 은 장기 적 이 ᆫ 자산 관리 와 위험 대비 를 목적 으로 고안 되 ᆫ 금융 상품 이 ᆸ니다 .\n", + "금융 저축 보험 은 규칙 적 이 ᆫ 저축 을 통하 어 목돈 을 마련 하 ᆯ 수 있 으며 , 생명 보험 기능 도 겸비 하 고 있 습니다 .\n", + "저축 금융 보험 은 저축 과 금융 을 통하 어 목돈 마련 에 도움 을 주 는 보험 이 ᆸ니다 . 또한 , 사망 보장 기능 도 제공 하 ᆸ니다 .\n", + "금융 저 축산물 보험 은 장기 적 이 ᆫ 저축 목적 과 더불 어 , 축산물 제공 기능 을 갖추 고 있 는 특별 금융 상품 이 ᆸ니다 .\n", + "금융 단 폭격 보험 은 저축 은 커녕 위험 대비 에 초점 을 맞추 ᆫ 상품 이 ᆸ니다 . 높 은 위험 을 감수 하 고자 하 는 고객 에게 적합 하 ᆸ니다 .\n", + "금 보험 은 저축 성과 를 극대 화 하 ᆸ니다 . 특히 노후 대비 저축 에 유리 하 게 구성 되 어 있 습니다 .\n", + "금융 보 씨 험하 ᆫ 말 좀 하 지 말 시 고 , 저축 이나 좀 하 시 던가요 . 뭐 가 그리 급하 시 ᆫ지 모르 겠 네요 .\n" + ] + } + ], + "source": [ + "# Print tokenized documents\n", + "for doc in docs:\n", + " print(\" \".join([token.form for token in kiwi.tokenize(doc.page_content)]))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Create a tokenization function\n", + "\n", + "def kiwi_tokenize(text):\n", + " return [token.form for token in kiwi.tokenize(text)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Experiment: Compare Search Results Using Different Retrievers\n", + "\n", + "In this section, we compare how different retrieval methods rank documents when given the same query. We are using:\n", + "\n", + "* `BM25`: A traditional ranking function based on term frequency (TF) and inverse document frequency (IDF).\n", + "* `Kiwi BM25`: `BM25` with an added benefit of kiwipiepy tokenization, enabling more accurate splitting of Korean words into morphemes (especially important for Korean queries).\n", + "* `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.\n", + "* `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.\n", + "\n", + "### Key points of Comparison\n", + "\n", + "**Exact Keyword Matching vs. Semantic Matching**\n", + "\n", + "* `BM25` (and `Kiwi BM25`) excel in finding documents that share exact terms or closely related morphological variants.\n", + "* `FAISS` retrieves documents that may not have exact lexical overlap but are semantically similar (e.g., synonyms or paraphrases).\n", + "\n", + "**Impact of Korean Morphological Analysis**\n", + "\n", + "* Korean often merges stems and endings into single words (“안녕하세요” → “안녕 + 하 + 세요”). `Kiwi BM25` handles this by splitting the query and documents more precisely.\n", + "* This can yield more relevant results when dealing with conjugated verbs, particles, or compound nouns.\n", + "\n", + "**Ensemble Approaches**\n", + "\n", + "* By combining lexical (`BM25`) and semantic (`FAISS`) retrievers, we can produce a more balanced set of results.\n", + "* The weighting (e.g., 70:30 or 30:70) can be tuned to emphasize one aspect over the other.\n", + "* Using MMR (Maximal Marginal Relevance) ensures diversity in the retrieved results, reducing redundancy." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.retrievers import BM25Retriever, EnsembleRetriever\n", + "from langchain_community.vectorstores import FAISS\n", + "from langchain_openai import OpenAIEmbeddings\n", + "\n", + "# Initialize BM25 retriever using raw documents\n", + "bm25 = BM25Retriever.from_documents(docs)\n", + "\n", + "# Initialize BM25 retriever with a custom preprocessing function (e.g., Kiwi tokenizer)\n", + "kiwi_bm25 = BM25Retriever.from_documents(docs, preprocess_func=kiwi_tokenize)\n", + "\n", + "# Initialize FAISS retriever with OpenAI embeddings\n", + "faiss = FAISS.from_documents(docs, OpenAIEmbeddings()).as_retriever()\n", + "\n", + "# Create an ensemble retriever combining BM25 and FAISS with a 70:30 weighting\n", + "bm25_faiss_73 = EnsembleRetriever(\n", + " retrievers=[bm25, faiss], # List of retrieval models to combine\n", + " weights=[0.7, 0.3], # Weighting for BM25 (70%) and FAISS (30%) results\n", + " search_type=\"mmr\", # Use MMR (Maximal Marginal Relevance) to diversify search results\n", + ")\n", + "\n", + "# Create an ensemble retriever combining BM25 and FAISS with a 30:70 weighting\n", + "bm25_faiss_37 = EnsembleRetriever(\n", + " retrievers=[bm25, faiss], # List of retrieval models to combine\n", + " weights=[0.3, 0.7], # Weighting for BM25 (30%) and FAISS (70%) results\n", + " search_type=\"mmr\", # Use MMR (Maximal Marginal Relevance) to diversify search results\n", + ")\n", + "\n", + "# Create an ensemble retriever combining Kiwi BM25 and FAISS with a 70:30 weighting\n", + "kiwibm25_faiss_73 = EnsembleRetriever(\n", + " retrievers=[kiwi_bm25, faiss], # List of retrieval models to combine\n", + " weights=[0.7, 0.3], # Weighting for Kiwi BM25 (70%) and FAISS (30%) results\n", + " search_type=\"mmr\", # Use MMR (Maximal Marginal Relevance) to diversify search results\n", + ")\n", + "\n", + "# Create an ensemble retriever combining Kiwi BM25 and FAISS with a 30:70 weighting\n", + "kiwibm25_faiss_37 = EnsembleRetriever(\n", + " retrievers=[kiwi_bm25, faiss], # List of retrieval models to combine\n", + " weights=[0.3, 0.7], # Weighting for Kiwi BM25 (30%) and FAISS (70%) results\n", + " search_type=\"mmr\", # Use MMR (Maximal Marginal Relevance) to diversify search results\n", + ")\n", + "\n", + "# Dictionary to store all retrievers for easy access\n", + "retrievers = {\n", + " \"bm25\": bm25, # Standard BM25 retriever\n", + " \"kiwi_bm25\": kiwi_bm25, # BM25 retriever with Kiwi tokenizer\n", + " \"faiss\": faiss, # FAISS retriever with OpenAI embeddings\n", + " \"bm25_faiss_73\": bm25_faiss_73, # Ensemble retriever (BM25:70%, FAISS:30%)\n", + " \"bm25_faiss_37\": bm25_faiss_37, # Ensemble retriever (BM25:30%, FAISS:70%)\n", + " \"kiwi_bm25_faiss_73\": kiwibm25_faiss_73, # Ensemble retriever (Kiwi BM25:70%, FAISS:30%)\n", + " \"kiwi_bm25_faiss_37\": kiwibm25_faiss_37, # Ensemble retriever (Kiwi BM25:30%, FAISS:70%)\n", + "}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# Function to print search results from multiple retrievers\n", + "def print_search_results(retrievers, query):\n", + " \"\"\"\n", + " Prints the top search result from each retriever for a given query.\n", + " \n", + " Args:\n", + " retrievers (dict): A dictionary of retriever instances.\n", + " query (str): The search query.\n", + " \"\"\"\n", + " print(f\"Query: {query}\")\n", + " for name, retriever in retrievers.items():\n", + " # Retrieve and print the top search result for each retriever\n", + " print(f\"{name}\\t: {retriever.invoke(query)[0].page_content}\")\n", + " print(\"===\" * 20)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Display Search Results\n", + "\n", + "금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "\n", + "-> Financial insurance is a financial product designed for long term asset management and risk coverage\n", + "\n", + "\n", + "금융저축보험은 규칙적인 저축을 통해 목돈을 마련할 수 있으며, 생명보험 기능도 겸비하고 있습니다.\n", + "\n", + "-> Financial savings insurance allows individuals to accumulate a lump sum through regular savings, and also offers life insurance benefits\n", + "\n", + "\n", + "저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "\n", + "-> Savings financial insurance helps individuals gather a lump sum through savings and finance, and also provides death benefit coverage\n", + "\n", + "\n", + "금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "\n", + "-> Financial savings livestock insurance is a special financial product designed for long term savings, which also includes provisions for livestock products\n", + "\n", + "\n", + "금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "\n", + "-> Financial 'carpet bombing' insurance focuses on risk coverage rather than savings. It is suitable for customers willing to take on high risk\n", + "\n", + "\n", + "금보험은 저축성과를 극대화합니다. 특히 노후 대비 저축에 유리하게 구성되어 있습니다.\n", + "\n", + "-> Gold insurance maximizes returns on savings. It is especially advantageous for retirement savings\n", + "\n", + "\n", + "금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "\n", + "-> Hey, Mr. 'Financial Bo,' please refrain from harsh words and consider saving money. I'm not sure why you're in such a hurry.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 금융보험\n", + "bm25\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "kiwi_bm25\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "faiss\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "bm25_faiss_73\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "bm25_faiss_37\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "kiwi_bm25_faiss_73\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "kiwi_bm25_faiss_37\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"금융보험\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 금융 보험\n", + "bm25\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "kiwi_bm25\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "faiss\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "bm25_faiss_73\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "bm25_faiss_37\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "kiwi_bm25_faiss_73\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "kiwi_bm25_faiss_37\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"금융 보험\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 금융저축보험\n", + "bm25\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "kiwi_bm25\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "faiss\t: 금융저축보험은 규칙적인 저축을 통해 목돈을 마련할 수 있으며, 생명보험 기능도 겸비하고 있습니다.\n", + "bm25_faiss_73\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "bm25_faiss_37\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "kiwi_bm25_faiss_73\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "kiwi_bm25_faiss_37\t: 금융저축보험은 규칙적인 저축을 통해 목돈을 마련할 수 있으며, 생명보험 기능도 겸비하고 있습니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"금융저축보험\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 축산물 보험\n", + "bm25\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "kiwi_bm25\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "faiss\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "bm25_faiss_73\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "bm25_faiss_37\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "kiwi_bm25_faiss_73\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "kiwi_bm25_faiss_37\t: 금융저축산물보험은 장기적인 저축 목적과 더불어, 축산물 제공 기능을 갖추고 있는 특별 금융 상품입니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"축산물 보험\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 저축금융보험\n", + "bm25\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "kiwi_bm25\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "faiss\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "bm25_faiss_73\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "bm25_faiss_37\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "kiwi_bm25_faiss_73\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "kiwi_bm25_faiss_37\t: 저축금융보험은 저축과 금융을 통해 목돈 마련에 도움을 주는 보험입니다. 또한, 사망 보장 기능도 제공합니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"저축금융보험\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 금융보씨 개인정보 조회\n", + "bm25\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "kiwi_bm25\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "faiss\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "bm25_faiss_73\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "bm25_faiss_37\t: 금융단폭격보험은 저축은 커녕 위험 대비에 초점을 맞춘 상품입니다. 높은 위험을 감수하고자 하는 고객에게 적합합니다.\n", + "kiwi_bm25_faiss_73\t: 금융보씨 험한말 좀 하지마시고, 저축이나 좀 하시던가요. 뭐가 그리 급하신지 모르겠네요.\n", + "kiwi_bm25_faiss_37\t: 금융보험은 장기적인 자산 관리와 위험 대비를 목적으로 고안된 금융 상품입니다.\n", + "============================================================\n" + ] + } + ], + "source": [ + "print_search_results(retrievers, \"금융보씨 개인정보 조회\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "By running the code and observing the top documents returned for each query, you’ll see how each retriever type has its strengths:\n", + "\n", + "`BM25` / `Kiwi BM25`: Great for precise keyword matching, beneficial for Korean morphological nuances.\n", + "\n", + "`FAISS`: Finds semantically related documents even if the wording differs.\n", + "\n", + "`Ensemble`: Balances both worlds, often achieving better overall coverage for a wide range of queries.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langchain-opentutorial-bMU5IxA3-py3.11", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.11" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}