MarkdownHeaderTextSplitter

텍스트 분할

효율적인 문서 청킹을 위한 다양한 텍스트 분할 전략을 다룬다.

AI
RAG
LangChain
저자

Kwangmin Kim

공개

2024년 12월 31일

마크다운 파일의 구조를 이해하고 효율적으로 다루는 것은 문서 작업에 있어 매우 중요할 수 있습니다. 특히, 문서의 전체적인 맥락과 구조를 고려하여 의미 있는 방식으로 텍스트를 임베딩하는 과정은, 광범위한 의미와 주제를 더 잘 포착할 수 있는 포괄적인 벡터 표현을 생성하는 데 큰 도움이 됩니다.

이러한 맥락에서, 마크다운 파일의 특정 부분, 즉 헤더별로 내용을 나누고 싶을 때가 있습니다. 예를 들어, 문서 내에서 각각의 헤더 아래에 있는 내용을 기반으로 서로 연관된 정보 덩어리, 즉 ’청크’를 만들고 싶은 경우가 그러합니다. 이는 텍스트의 공통된 맥락을 유지하면서도, 문서의 구조적 요소를 효과적으로 활용하려는 시도입니다.

이런 과제를 해결하기 위해, MarkdownHeaderTextSplitter 라는 도구를 활용할 수 있습니다. 이 도구는 문서를 지정된 헤더 집합에 따라 분할하여, 각 헤더 그룹 아래의 내용을 별도의 청크로 관리할 수 있게 합니다. 이 방법을 통해, 문서의 전반적인 구조를 유지하면서도 내용을 더 세밀하게 다룰 수 있게 되며, 이는 다양한 처리 과정에서 유용하게 활용될 수 있습니다.

MarkdownHeaderTextSplitter를 사용하여 마크다운 형식의 텍스트를 헤더 단위로 분할합니다.

from langchain_text_splitters import MarkdownHeaderTextSplitter

# 마크다운 형식의 문서를 문자열로 정의합니다.
markdown_document = "# Title\n\n## 1. SubTitle\n\nHi this is Jim\n\nHi this is Joe\n\n### 1-1. Sub-SubTitle \n\nHi this is Lance \n\n## 2. Baz\n\nHi this is Molly"
print(markdown_document)
headers_to_split_on = [  # 문서를 분할할 헤더 레벨과 해당 레벨의 이름을 정의합니다.
    (
        "#",
        "Header 1",
    ),  # 헤더 레벨 1은 '#'로 표시되며, 'Header 1'이라는 이름을 가집니다.
    (
        "##",
        "Header 2",
    ),  # 헤더 레벨 2는 '##'로 표시되며, 'Header 2'라는 이름을 가집니다.
    (
        "###",
        "Header 3",
    ),  # 헤더 레벨 3은 '###'로 표시되며, 'Header 3'이라는 이름을 가집니다.
]

# 마크다운 헤더를 기준으로 텍스트를 분할하는 MarkdownHeaderTextSplitter 객체를 생성합니다.
markdown_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
# markdown_document를 헤더를 기준으로 분할하여 md_header_splits에 저장합니다.
md_header_splits = markdown_splitter.split_text(markdown_document)
# 분할된 결과를 출력합니다.
for header in md_header_splits:
    print(f"{header.page_content}")
    print(f"{header.metadata}", end="\n=====================\n")

1 Title

1.1 1. SubTitle

Hi this is Jim

Hi this is Joe

1.1.1 1-1. Sub-SubTitle

Hi this is Lance

1.2 2. Baz

Hi this is Molly

기본적으로 MarkdownHeaderTextSplitter는 분할되는 헤더를 출력 청크의 내용에서 제거합니다.

이는 strip_headers = False로 설정하여 비활성화할 수 있습니다.

markdown_splitter = MarkdownHeaderTextSplitter(
    # 분할할 헤더를 지정합니다.
    headers_to_split_on=headers_to_split_on,
    # 헤더를 제거하지 않도록 설정합니다.
    strip_headers=False,
)
# 마크다운 문서를 헤더를 기준으로 분할합니다.
md_header_splits = markdown_splitter.split_text(markdown_document)
# 분할된 결과를 출력합니다.
for header in md_header_splits:
    print(f"{header.page_content}")
    print(f"{header.metadata}", end="\n=====================\n")

각 마크다운 그룹 내에서는 원하는 텍스트 분할기(text splitter)를 적용할 수 있습니다.

from langchain_text_splitters import RecursiveCharacterTextSplitter

markdown_document = "# Intro \n\n## History \n\nMarkdown[9] is a lightweight markup language for creating formatted text using a plain-text editor. John Gruber created Markdown in 2004 as a markup language that is appealing to human readers in its source code form.[9] \n\nMarkdown is widely used in blogging, instant messaging, online forums, collaborative software, documentation pages, and readme files. \n\n## Rise and divergence \n\nAs Markdown popularity grew rapidly, many Markdown implementations appeared, driven mostly by the need for \n\nadditional features such as tables, footnotes, definition lists,[note 1] and Markdown inside HTML blocks. \n\n#### Standardization \n\nFrom 2012, a group of people, including Jeff Atwood and John MacFarlane, launched what Atwood characterised as a standardisation effort. \n\n# Implementations \n\nImplementations of Markdown are available for over a dozen programming languages."
print(markdown_document)

먼저, MarkdownHeaderTextSplitter 사용하여 마크다운 문서를 헤더를 기준으로 분할합니다.

headers_to_split_on = [
    ("#", "Header 1"),  # 분할할 헤더 레벨과 해당 레벨의 이름을 지정합니다.
    # ("##", "Header 2"),
]

# Markdown 문서를 헤더 레벨에 따라 분할합니다.
markdown_splitter = MarkdownHeaderTextSplitter(
    headers_to_split_on=headers_to_split_on, strip_headers=False
)
md_header_splits = markdown_splitter.split_text(markdown_document)
# 분할된 결과를 출력합니다.
for header in md_header_splits:
    print(f"{header.page_content}")
    print(f"{header.metadata}", end="\n=====================\n")

이전의 MarkdownHeaderTextSplitter 로 분할된 결과를 다시 RecursiveCharacterTextSplitter 로 분할합니다.

chunk_size = 200  # 분할된 청크의 크기를 지정합니다.
chunk_overlap = 20  # 분할된 청크 간의 중복되는 문자 수를 지정합니다.
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=chunk_size, chunk_overlap=chunk_overlap
)

# 문서를 문자 단위로 분할합니다.
splits = text_splitter.split_documents(md_header_splits)
# 분할된 결과를 출력합니다.
for header in splits:
    print(f"{header.page_content}")
    print(f"{header.metadata}", end="\n=====================\n")

Subscribe

Enjoy this blog? Get notified of new posts by email: