AutoMergingRetriever
AutoMergingRetriever
AutoMergingRetriever를 사용하면 여러 관련 조각이 쿼리와 일치할 때, 분할된 조각 대신 완전한 부모 문서를 반환해 검색 결과를 개선할 수 있어요.
파이프라인에서 가장 흔한 위치: 계층적 문서를 반환하는 주 Retriever 컴포넌트 뒤에 사용
필수 init 변수: document_store — 부모 문서를 검색할 Document Store
필수 run 변수: documents — Retriever가 매칭한 리프(leaf) 문서 목록
출력 변수: documents — 결과 문서 목록
API reference: Retrievers
GitHub link: https://github.com/deepset-ai/haystack/blob/main/haystack/components/retrievers/auto_merging_retriever.py
Package name: haystack-ai
출처: 문서
본문
Overview
AutoMergingRetriever는 계층적 문서 구조와 함께 동작하는 컴포넌트예요. 특정 임계값이 충족되면 개별 리프 문서 대신 부모 문서를 반환합니다.
문단이 여러 조각으로 나뉘어 있을 때 특히 유용해요. 같은 문단의 여러 조각이 쿼리와 일치하면, 개별 조각만으로 줄 때보다 완전한 문단이 더 많은 컨텍스트와 가치를 제공하는 경우가 많죠.
이 Retriever의 동작 방식은 다음과 같아요:
- 문서가 트리 구조로 정리되어야 하며, 리프 노드는 문서 인덱스에 저장됩니다 — HierarchicalDocumentSplitter 문서를 참고하세요.
- 검색할 때 같은 부모 아래의 리프 문서 몇 개가 쿼리와 일치하는지 세어요.
- 이 개수가 정의한 임계값을 넘으면 개별 리프 대신 부모 문서를 반환합니다.
AutoMergingRetriever는 현재 다음 Document Store에서 사용할 수 있어요:
- AstraDocumentStore
- ElasticsearchDocumentStore
- OpenSearchDocumentStore
- PgvectorDocumentStore
- QdrantDocumentStore
Usage
On its own
from haystack import Document
from haystack.components.preprocessors import HierarchicalDocumentSplitter
from haystack.components.retrievers.auto_merging_retriever import AutoMergingRetriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
# create a hierarchical document structure with 3 levels, where the parent document has 3 children
text = "The sun rose early in the morning. It cast a warm glow over the trees. Birds began to sing."
original_document = Document(content=text)
builder = HierarchicalDocumentSplitter(
block_sizes={10, 3}, split_overlap=0, split_by="word")
docs = builder.run([original_document])["documents"]
# store the root document and the level-1 parent documents, then initialize the retriever
doc_store_parents = InMemoryDocumentStore()
for doc in docs:
if doc.meta["__children_ids"] and doc.meta["__level"] in [0, 1]:
doc_store_parents.write_documents([doc])
retriever = AutoMergingRetriever(doc_store_parents, threshold=0.5)
# assume we retrieved 2 leaf docs from the same parent, the parent document should be returned,
# since it has 3 children and the threshold=0.5, and we retrieved 2 children (2/3 > 0.5)
leaf_docs = [doc for doc in docs if not doc.meta["__children_ids"]]
retrieved_docs = retriever.run(leaf_docs[4:6])
print(retrieved_docs["documents"])
# >> [Document(id=bcc..., content: 'warm glow over the trees. Birds began to sing.',
# >> meta: {'__block_size': 10, '__parent_id': '835...', '__children_ids': ['a93...', 'c3e...', 'c61...'], '__level': 1,
# >> 'source_id': '835...', 'page_number': 1, 'split_id': 1, 'split_idx_start': 45})]
In a pipeline
이것은 RAG Haystack 파이프라인 예시예요. 먼저 BM25로 리프 레벨 문서 조각을 검색하고, AutoMergingRetriever로 이를 상위 레벨 부모 문서로 병합한 뒤, 프롬프트를 만들고 OpenAI의 채팅 모델로 답변을 생성합니다.
from typing import List, Tuple
from haystack import Document, Pipeline
from haystack.components.preprocessors import HierarchicalDocumentSplitter
from haystack.components.builders.answer_builder import AnswerBuilder
from haystack.components.builders.chat_prompt_builder import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.components.retrievers import AutoMergingRetriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.document_stores.types import DuplicatePolicy
from haystack.dataclasses import ChatMessage
def indexing(
documents: List[Document],
) -> Tuple[InMemoryDocumentStore, InMemoryDocumentStore]:
splitter = HierarchicalDocumentSplitter(
block_sizes={10, 3},
split_overlap=0,
split_by="word",
)
docs = splitter.run(documents)
leaf_documents = [doc for doc in docs["documents"] if doc.meta["__level"] == 1]
leaf_doc_store = InMemoryDocumentStore()
leaf_doc_store.write_documents(leaf_documents, policy=DuplicatePolicy.OVERWRITE)
parent_documents = [doc for doc in docs["documents"] if doc.meta["__level"] == 0]
parent_doc_store = InMemoryDocumentStore()
parent_doc_store.write_documents(parent_documents, policy=DuplicatePolicy.OVERWRITE)
return leaf_doc_store, parent_doc_store
# Add documents
docs = [
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.",
),
]
leaf_docs, parent_docs = indexing(docs)
prompt_template = [
ChatMessage.from_system("You are a helpful assistant."),
ChatMessage.from_user(
# ... (프롬프트 템플릿 계속, 원문 참조)
),
]
# ... (파이프라인 구성 계속, 원문 참조)
더 알아보기 (Learn more)
- HierarchicalDocumentSplitter — 계층적 문서 구조 만들기
- Retrievers — Retriever 컴포넌트