133 深入解析 SentenceWindowNodeParser:一种高效的文本节点解析器 llamaindex.core.node_parser.text.sentence_window.py

深入解析SentenceWindowNodeParser:一种高效的文本节点解析器

在自然语言处理(NLP)领域,文本解析是一个基础且关键的步骤。它涉及将文档拆分成更小的单元,以便于进一步处理和分析。今天,我们将深入探讨一种名为 SentenceWindowNodeParser 的文本节点解析器,它能够将文档拆分成句子,并在每个节点中包含前后句子的窗口信息。这种解析器在处理长文档时尤为有用,因为它可以帮助我们更好地理解上下文。

前置知识

在深入了解 SentenceWindowNodeParser 之前,我们需要掌握以下几个概念:

  1. 节点(Node):在NLP中,节点是文档的基本单元。它可以是一个句子、一个段落或一个词语。
  2. 元数据(Metadata):元数据是关于数据的数据,用于描述节点的额外信息。
  3. 回调管理器(CallbackManager):用于管理和调用回调函数,以便在特定事件发生时执行相应的操作。
  4. Pydantic:一个用于数据验证和设置的Python库,常用于定义数据模型。

SentenceWindowNodeParser 的实现

SentenceWindowNodeParser 是一个基于 NodeParser 接口的类,它通过将文档拆分成句子并包含前后句子的窗口信息来创建节点。下面是其实现的详细解析:

导入必要的模块

首先,我们需要导入一些必要的模块和函数:

from typing import Any, Callable, List, Optional, Sequence
from llama_index.core.bridge.pydantic import Field
from llama_index.core.callbacks.base import CallbackManager
from llama_index.core.node_parser.interface import NodeParser
from llama_index.core.node_parser.node_utils import (
    build_nodes_from_splits,
    default_id_func,
)
from llama_index.core.node_parser.text.utils import split_by_sentence_tokenizer
from llama_index.core.schema import BaseNode, Document
from llama_index.core.utils import get_tqdm_iterable

定义默认参数

接下来,我们定义一些默认参数,这些参数将在类的初始化过程中使用:

DEFAULT_WINDOW_SIZE = 3
DEFAULT_WINDOW_METADATA_KEY = "window"
DEFAULT_OG_TEXT_METADATA_KEY = "original_text"

定义 SentenceWindowNodeParser 类

现在,我们定义 SentenceWindowNodeParser 类,并为其添加必要的属性和方法:

class SentenceWindowNodeParser(NodeParser):
    """Sentence window node parser.

    Splits a document into Nodes, with each node being a sentence.
    Each node contains a window from the surrounding sentences in the metadata.

    Args:
        sentence_splitter (Optional[Callable]): splits text into sentences
        include_metadata (bool): whether to include metadata in nodes
        include_prev_next_rel (bool): whether to include prev/next relationships
    """

    sentence_splitter: Callable[[str], List[str]] = Field(
        default_factory=split_by_sentence_tokenizer,
        description="The text splitter to use when splitting documents.",
        exclude=True,
    )
    window_size: int = Field(
        default=DEFAULT_WINDOW_SIZE,
        description="The number of sentences on each side of a sentence to capture.",
        gt=0,
    )
    window_metadata_key: str = Field(
        default=DEFAULT_WINDOW_METADATA_KEY,
        description="The metadata key to store the sentence window under.",
    )
    original_text_metadata_key: str = Field(
        default=DEFAULT_OG_TEXT_METADATA_KEY,
        description="The metadata key to store the original sentence in.",
    )

    @classmethod
    def class_name(cls) -> str:
        return "SentenceWindowNodeParser"

    @classmethod
    def from_defaults(
        cls,
        sentence_splitter: Optional[Callable[[str], List[str]]] = None,
        window_size: int = DEFAULT_WINDOW_SIZE,
        window_metadata_key: str = DEFAULT_WINDOW_METADATA_KEY,
        original_text_metadata_key: str = DEFAULT_OG_TEXT_METADATA_KEY,
        include_metadata: bool = True,
        include_prev_next_rel: bool = True,
        callback_manager: Optional[CallbackManager] = None,
        id_func: Optional[Callable[[int, Document], str]] = None,
    ) -> "SentenceWindowNodeParser":
        callback_manager = callback_manager or CallbackManager([])

        sentence_splitter = sentence_splitter or split_by_sentence_tokenizer()

        id_func = id_func or default_id_func

        return cls(
            sentence_splitter=sentence_splitter,
            window_size=window_size,
            window_metadata_key=window_metadata_key,
            original_text_metadata_key=original_text_metadata_key,
            include_metadata=include_metadata,
            include_prev_next_rel=include_prev_next_rel,
            callback_manager=callback_manager,
            id_func=id_func,
        )

    def _parse_nodes(
        self,
        nodes: Sequence[BaseNode],
        show_progress: bool = False,
        **kwargs: Any,
    ) -> List[BaseNode]:
        """Parse document into nodes."""
        all_nodes: List[BaseNode] = []
        nodes_with_progress = get_tqdm_iterable(nodes, show_progress, "Parsing nodes")

        for node in nodes_with_progress:
            nodes = self.build_window_nodes_from_documents([node])
            all_nodes.extend(nodes)

        return all_nodes

    def build_window_nodes_from_documents(
        self, documents: Sequence[Document]
    ) -> List[BaseNode]:
        """Build window nodes from documents."""
        all_nodes: List[BaseNode] = []
        for doc in documents:
            text = doc.text
            text_splits = self.sentence_splitter(text)
            nodes = build_nodes_from_splits(
                text_splits,
                doc,
                id_func=self.id_func,
            )

            # add window to each node
            for i, node in enumerate(nodes):
                window_nodes = nodes[
                    max(0, i - self.window_size) : min(
                        i + self.window_size + 1, len(nodes)
                    )
                ]

                node.metadata[self.window_metadata_key] = " ".join(
                    [n.text for n in window_nodes]
                )
                node.metadata[self.original_text_metadata_key] = node.text

                # exclude window metadata from embed and llm
                node.excluded_embed_metadata_keys.extend(
                    [self.window_metadata_key, self.original_text_metadata_key]
                )
                node.excluded_llm_metadata_keys.extend(
                    [self.window_metadata_key, self.original_text_metadata_key]
                )

            all_nodes.extend(nodes)

        return all_nodes

详细解析

属性解析
  • sentence_splitter:这是一个可调用对象,用于将文本拆分成句子。默认情况下,它使用 split_by_sentence_tokenizer 函数。
  • window_size:表示每个节点包含的前后句子的数量。默认值为3。
  • window_metadata_key:用于存储句子窗口信息的元数据键。默认值为 “window”。
  • original_text_metadata_key:用于存储原始句子信息的元数据键。默认值为 “original_text”。
方法解析
  • class_name:这是一个类方法,返回类的名称。
  • from_defaults:这是一个类方法,用于从默认参数创建 SentenceWindowNodeParser 实例。
  • _parse_nodes:这是一个实例方法,用于将文档解析成节点。
  • build_window_nodes_from_documents:这是一个实例方法,用于从文档构建包含窗口信息的节点。

实际应用示例

为了更好地理解 SentenceWindowNodeParser 的工作原理,我们来看一个实际的应用示例:

# 示例文档
document = Document(text="这是一个示例文档。它包含多个句子。每个句子都将被拆分成一个节点。")

# 创建 SentenceWindowNodeParser 实例
node_parser = SentenceWindowNodeParser.from_defaults()

# 解析文档
nodes = node_parser.get_nodes_from_documents([document])

# 输出节点信息
for node in nodes:
    print(f"Node ID: {node.id_}")
    print(f"Original Text: {node.metadata[node_parser.original_text_metadata_key]}")
    print(f"Window: {node.metadata[node_parser.window_metadata_key]}")
    print("-" * 40)

在这个示例中,我们首先创建了一个包含多个句子的文档,然后使用 SentenceWindowNodeParser 将其拆分成节点,并输出每个节点的原始文本和窗口信息。

输出结果

假设文档被拆分成以下三个句子:

  1. “这是一个示例文档。”
  2. “它包含多个句子。”
  3. “每个句子都将被拆分成一个节点。”

那么,输出的节点信息可能如下:

Node ID: 1
Original Text: 这是一个示例文档。
Window: 这是一个示例文档。 它包含多个句子。
----------------------------------------
Node ID: 2
Original Text: 它包含多个句子。
Window: 这是一个示例文档。 它包含多个句子。 每个句子都将被拆分成一个节点。
----------------------------------------
Node ID: 3
Original Text: 每个句子都将被拆分成一个节点。
Window: 它包含多个句子。 每个句子都将被拆分成一个节点。
----------------------------------------

从输出结果可以看出:

  • 每个节点包含一个 Node ID,用于唯一标识该节点。
  • 每个节点包含一个 Original Text,即原始句子信息。
  • 每个节点包含一个 Window,即前后句子的窗口信息。

总结

SentenceWindowNodeParser 是一个高效的文本节点解析器,它能够将文档拆分成句子,并在每个节点中包含前后句子的窗口信息。通过这种方式,我们可以更好地理解文档的上下文,从而提高NLP任务的准确性。希望这篇博客能够帮助你全面理解 SentenceWindowNodeParser 的工作原理及实际应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要重新演唱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值