BM25 리트리버
BM25 리트리버 (InMemoryBM25Retriever)
InMemoryBM25Retriever는 인메모리 Document Store와 호환되는 키워드 기반 리트리버예요. 문서와 쿼리 사이의 유사도를 BM25 알고리즘으로 계산하는데, 이 알고리즘은 두 문자열 사이의 가중치가 적용된 단어 중복을 계산해요. 사람 이름·제품 이름의 정확한 일치, ID, 잘 정의된 오류 메시지 같은 '정확한 문자열'을 찾을 때 특히 강해요.
출처: 공식문서
주요 정보
| 항목 | 값 |
|---|---|
| 파이프라인에서 가장 흔한 위치 | 쿼리 파이프라인: RAG 파이프라인에서는 PromptBuilder 앞 의미 검색 파이프라인에서는 마지막 컴포넌트 추출적 QA 파이프라인에서는 TransformersExtractiveReader 앞 |
| 필수 초기화 변수 | document_store: InMemoryDocumentStore 인스턴스 |
| 필수 실행 변수 | query: 쿼리 문자열 |
| 출력 변수 | documents: (쿼리와 일치하는) 문서 리스트 |
| API 레퍼런스 | Retrievers |
| GitHub 링크 | https://github.com/deepset-ai/haystack/blob/main/haystack/components/retrievers/in_memory/bm25_retriever.py |
| 패키지 이름 | haystack-ai |
개요
InMemoryBM25Retriever는 임시 인메모리 데이터베이스에서 쿼리와 일치하는 Document를 가져오는 키워드 기반 리트리버예요. Document와 쿼리 사이의 유사도를 BM25 알고리즘에 기반해 결정하는데, 이 알고리즘은 두 문자열 사이의 가중치가 적용된 단어 중복을 계산해요.
InMemoryBM25Retriever는 단어 중복을 기준으로 문자열을 매칭하기 때문에, 사람 이름·제품 이름·ID 또는 잘 정의된 오류 메시지 같은 것의 정확한 일치를 찾을 때 자주 쓰여요. BM25 알고리즘은 매우 가볍고 단순해요. 그런데도 도메인 밖(out-of-domain) 데이터에서는 더 복잡한 임베딩 기반 접근법으로도 이기기 어려운 경우가 많아요.
query 외에도 InMemoryBM25Retriever는 top_k(가져올 최대 Document 수)와 filters(검색 공간을 좁히는 용도) 같은 다른 선택적 파라미터를 받아요.
BM25 검색에 영향을 주는 일부 관련 파라미터는 해당 InMemoryDocumentStore가 초기화될 때 정의해야 해요. 여기에는 구체적인 BM25 알고리즘과 그 파라미터가 포함돼요.
사용법
단독으로 쓰기
from haystack import Document
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
document_store = InMemoryDocumentStore()
documents = [
Document(content="There are over 7,000 languages spoken around the world today."),
Document(
content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.",
),
Document(
content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.",
),
]
document_store.write_documents(documents=documents)
retriever = InMemoryBM25Retriever(document_store=document_store)
retriever.run(query="How many languages are spoken around the world today?")
파이프라인 안에서 쓰기
RAG 파이프라인에서
검색 증강 생성 파이프라인에서 리트리버를 쓰는 예시예요.
import os
from haystack import Document
from haystack import Pipeline
from haystack.components.builders.answer_builder import AnswerBuilder
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.dataclasses import ChatMessage
from haystack.document_stores.in_memory import InMemoryDocumentStore
# Create a RAG query pipeline
prompt_template = [
ChatMessage.from_user(
"""
Given these documents, answer the question.\nDocuments:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
\nQuestion: {{question}}
\nAnswer:
""",
),
]
os.environ["OPENAI_API_KEY"] = "sk-XXXXXX"
rag_pipeline = Pipeline()
rag_pipeline.add_component(
instance=InMemoryBM25Retriever(document_store=InMemoryDocumentStore()),
name="retriever",
)
rag_pipeline.add_component(
instance=ChatPromptBuilder(template=prompt_template, required_variables="*"),
name="prompt_builder",
)
rag_pipeline.add_component(instance=OpenAIChatGenerator(), name="llm")
rag_pipeline.add_component(instance=AnswerBuilder(), name="answer_builder")
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder.prompt", "llm.messages")
rag_pipeline.connect("llm.replies", "answer_builder.replies")
rag_pipeline.connect("retriever", "answer_builder.documents")
# Draw the pipeline
rag_pipeline.draw("./rag_pipeline.png")
# Add Documents
documents = [
Document(content="There are over 7,000 languages spoken around the world today."),
Document(
content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.",
),
Document(
content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.",
),
]
rag_pipeline.get_component("retriever").document_store.write_documents(documents)
# Run the pipeline
question = "How many languages are there?"
result = rag_pipeline.run(
{
"retriever": {"query": question},
"prompt_builder": {"question": question},
"answer_builder": {"query": question},
},
)
print(result["answer_builder"]["answers"][0])
문서 검색 파이프라인에서
문서 검색 파이프라인에서 이 리트리버를 쓰는 방법이에요.
from haystack import Document, Pipeline
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
# Create components and a query pipeline
document_store = InMemoryDocumentStore()
retriever = InMemoryBM25Retriever(document_store=document_store)
pipeline = Pipeline()
pipeline.add_component(instance=retriever, name="retriever")
# Add Documents
documents = [
Document(content="There are over 7,000 languages spoken around the world today."),
Document(
content="Elephants have been observed to behave in a way that indicates a high level of self-awareness, such as recognizing themselves in mirrors.",
),
Document(
content="In certain parts of the world, like the Maldives, Puerto Rico, and San Diego, you can witness the phenomenon of bioluminescent waves.",
),
]
document_store.write_documents(documents)
# Run the pipeline
result = pipeline.run(data={"retriever": {"query": "How many languages are there?"}})
print(result["retriever"]["documents"][0])