【lucene☞】重叠token token的pos位置

什么是重叠 token?

重叠 token 是指在分词过程中,同一个文本片段被分词器切分成多个不同的 token,而这些 token 在文本中的位置有交集。换句话说,同一段文本被分词器多次识别为不同的词汇,每个词汇都被当作一个独立的 token。

为什么会出现重叠 token?

重叠 token 的出现主要是因为分词器的 最大正向匹配 策略。这种策略的目标是 尽可能多地匹配出所有可能的词语,以提高召回率。例如,`ik_max_word` 模式会尝试从最长的可能词语开始向下匹配,从而生成多个重叠的 token。

举例说明

假设输入文本是 “中国农业银行”,使用 `ik_max_word` 分词器进行分词:

Token 文本 起始字符位置 结束字符位置 位置编号 (pos) 

中国农业银行 0 6 1 

中国农业 0 4 2 

中国 0 2 3 

国农 1 3 4 

农业银行 2 6 5 

农业银 2 5 6 

农业 2 4 7 

银行 4 6 8 

在这个例子中:

– “中国农业银行” 和 “中国农业” 都是从第 0 个字符开始的,因此它们的起始位置重叠。

– “中国农业银行” 和 “中国” 都包含前两个字符 “中国”。

– “农业银行” 和 “农业银行” 的整个文本重叠。

– “农业银” 和 “农业银行” 的前几个字符重叠。

重叠 token 的特点

1. 位置编号不同:

   – 每个 token 都有一个独立的位置编号(pos),从 1 开始递增。这些位置编号是 Lucene 在处理查询和位置运算时所依赖的关键信息。

2. 字符范围有交集:

   – 这些 token 在原始文本中的字符范围有重叠。例如,“中国农业银行” 和 “中国农业” 都覆盖了文本的前几个字符。

3. 多个 token 表示同一段文本:

   – 同一段文本被分词器切成了多个不同的词条,每个词条都被当作一个独立的 token。这些 token 在位置上会有交集,因此被称为“重叠 token”。

重叠 token 的影响

1. 查询时的复杂性:

   – 在使用 `SpanNearQuery` 或其他基于位置的查询时,重叠 token 会导致位置计算变得更加复杂。例如,“中国” 和 “农业银行” 的真实位置跨度可能比你预期的要大,因为它们可能不是直接相邻的 token。

2. 索引大小:

   – 重叠 token 会增加索引的大小,因为相同的文本片段被存储为多个 token。

如何避免重叠 token?

如果你希望避免重叠 token,可以使用 `ik_smart` 模式。`ik_smart` 模式更倾向于保持术语的完整性,减少重叠 token 的产生。例如,对 “中国农业银行”,`ik_smart` 通常会将其切分为一个单独的 token:

“`

pos=1: 中国农业银行

“`

示例代码

下面是一个简单的示例代码,展示如何使用 `ik_smart` 和 `ik_max_word` 分词器,并打印分词结果:

“`java

import org.apache.lucene.analysis.*;

import org.apache.lucene.analysis.ik.IKAnalyzer;

import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;

import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;

import java.io.StringReader;

 

public class IKAnalyzerDemo {

    public static void main(String[] args) throws Exception {

        // 输入文本

        String text = “中国农业银行”;

 

        // 使用 ik_smart 分词器

        IKAnalyzer ikSmart = new IKAnalyzer(true); // true 表示使用智能分词模式

        System.out.println(“=== ik_smart 分词结果 ===”);

        printTokens(ikSmart, text);

 

        // 使用 ik_max_word 分词器

        IKAnalyzer ikMaxWord = new IKAnalyzer(false); // false 表示使用最大正向匹配模式

        System.out.println(“=== ik_max_word 分词结果 ===”);

        printTokens(ikMaxWord, text);

 

        // 关闭分词器

        ikSmart.close();

        ikMaxWord.close();

    }

 

    private static void printTokens(Analyzer analyzer, String text) throws Exception {

        try (TokenStream ts = analyzer.tokenStream(“f”, new StringReader(text))) {

            CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);

            PositionIncrementAttribute posInc = ts.addAttribute(PositionIncrementAttribute.class);

 

            ts.reset();

            int pos = 0;

            while (ts.incrementToken()) {

                pos += posInc.getPositionIncrement();

                System.out.println(“pos=” + pos + ” term=” + term.toString());

            }

            ts.end();

        }

    }

}

“`

输出结果

运行上述代码后,你可能会看到类似以下的输出:

“`

=== ik_smart 分词结果 ===

pos=1 term=中国农业银行

 

=== ik_max_word 分词结果 ===

pos=1 term=中国农业银行

pos=2 term=中国农业

pos=3 term=中国

pos=4 term=国农

pos=5 term=农业银行

pos=6 term=农业银

pos=7 term=农业

pos=8 term=银行

“`

总结

> 重叠 token = 同一段文本被分词器切成了多个不同的词条,这些词条在位置上会有交集。

这种设计虽然有助于提高召回率,但也增加了查询时的复杂性和索引大小。如果你希望减少这种复杂性,可以考虑使用 `ik_smart` 模式,它更倾向于保持术语的完整性,减少重叠 token 的产生。

那什么是token的位置呢?

我们首先明确 token 的位置 的定义和用途,然后结合实际案例进行解释。

 

什么是 token 的位置?

 

Token 的位置 是指在分词过程中,分词器为每个 token 分配的一个 顺序编号。这个编号从 1 开始,表示 token 在分词结果中的相对顺序。它是 Lucene 和其他搜索引擎框架在处理基于位置的查询(如短语查询、邻近查询等)时的关键信息。

 

Token 的位置 vs. 原始文本中的字符位置

 

– Token 的位置 是一个逻辑上的编号,表示 token 在分词结果中的顺序。

– 原始文本中的字符位置 是 token 在原文本中的起始和结束字符的索引。

 

在 Lucene 中,我们主要关注的是 token 的位置,因为它用于位置运算和查询。

 

示例解释

 

假设输入文本是 “中国农业银行”,我们分别用 `ik_smart` 和 `ik_max_word` 分词器进行分词:

 

1. 使用 `ik_smart` 分词器

 

分词结果:

 

“`

pos=1: 中国农业银行

“`

 

– token: “中国农业银行”

– 位置编号 (pos): 1

 

解释:

– 分词器将整个文本切分为一个 token。

– 这个 token 的位置编号是 1。

 

2. 使用 `ik_max_word` 分词器

 

分词结果:

 

“`

pos=1: 中国农业银行

pos=2: 中国农业

pos=3: 中国

pos=4: 国农

pos=5: 农业银行

pos=6: 农业银

pos=7: 农业

pos=8: 银行

“`

 

– token: “中国农业银行” → 位置编号 1

– token: “中国农业” → 位置编号 2

– token: “中国” → 位置编号 3

– token: “国农” → 位置编号 4

– token: “农业银行” → 位置编号 5

– token: “农业银” → 位置编号 6

– token: “农业” → 位置编号 7

– token: “银行” → 位置编号 8

 

解释:

– 分词器将文本切分为多个 token,每个 token 都有一个独立的位置编号。

– 这些 token 在位置上会有重叠(重叠 token),因为同一个文本片段被切分成了多个不同的词条。

 

Token 的位置的作用

 

1. 位置运算的基础:

   – 在 Lucene 中,基于位置的查询(如 `SpanNearQuery`、`SpanFirstQuery` 等)依赖 token 的位置编号来计算 token 之间的相对位置关系。

 

2. 查询匹配的关键:

   – 例如,`SpanNearQuery` 用于查找两个 token 在指定距离内的匹配。位置编号用于计算两个 token 之间的跨度。

 

示例代码

 

下面是一个简单的示例代码,展示如何使用 `ik_smart` 和 `ik_max_word` 分词器,并打印分词结果中的 token 和其位置编号:

 

“`java

import org.apache.lucene.analysis.*;

import org.apache.lucene.analysis.ik.IKAnalyzer;

import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;

import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;

import java.io.StringReader;

 

public class IKAnalyzerDemo {

    public static void main(String[] args) throws Exception {

        // 输入文本

        String text = “中国农业银行”;

 

        // 使用 ik_smart 分词器

        IKAnalyzer ikSmart = new IKAnalyzer(true); // true 表示使用智能分词模式

        System.out.println(“=== ik_smart 分词结果 ===”);

        printTokens(ikSmart, text);

 

        // 使用 ik_max_word 分词器

        IKAnalyzer ikMaxWord = new IKAnalyzer(false); // false 表示使用最大正向匹配模式

        System.out.println(“=== ik_max_word 分词结果 ===”);

        printTokens(ikMaxWord, text);

 

        // 关闭分词器

        ikSmart.close();

        ikMaxWord.close();

    }

 

    private static void printTokens(Analyzer analyzer, String text) throws Exception {

        try (TokenStream ts = analyzer.tokenStream(“f”, new StringReader(text))) {

            CharTermAttribute term = ts.addAttribute(CharTermAttribute.class);

            PositionIncrementAttribute posInc = ts.addAttribute(PositionIncrementAttribute.class);

 

            ts.reset();

            int pos = 0;

            while (ts.incrementToken()) {

                pos += posInc.getPositionIncrement();

                System.out.println(“pos=” + pos + ” term=” + term.toString());

            }

            ts.end();

        }

    }

}

“`

 

输出结果

 

运行上述代码后,你可能会看到类似以下的输出:

 

“`

=== ik_smart 分词结果 ===

pos=1 term=中国农业银行

 

=== ik_max_word 分词结果 ===

pos=1 term=中国农业银行

pos=2 term=中国农业

pos=3 term=中国

pos=4 term=国农

pos=5 term=农业银行

pos=6 term=农业银

pos=7 term=农业

pos=8 term=银行

“`

 

总结

 

> Token 的位置编号是分词器在分词过程中为每个 token 分配的顺序编号,用于表示 token 在分词结果中的相对顺序。它是 Lucene 查询和位置运算的关键。

 

希望这能清晰地解答你的问题!

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容