【问题标题】:Adding tokens to a lucene tokenstream将令牌添加到 lucene 令牌流
【发布时间】:2013-07-02 20:04:05
【问题描述】:

我写了一个TokenFilter 在流中添加标记。

1。测试表明它有效,但我不完全明白为什么。

如果有人能阐明语义,我将不胜感激。特别是在(*),恢复状态,是不是意味着我们要么覆盖当前的token,要么覆盖在捕获状态之前创建的token?

这大概就是我所做的

private final LinkedList<String> extraTokens = new LinkedList<String>();
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private State savedState;

@Override
public boolean incrementToken() throws IOException {
    if (!extraTokens.isEmpty()) {
        // Do we not loose/overwrite the current termAtt token here? (*)
        restoreState(savedState);
        termAtt.setEmpty().append(extraTokens.remove());
        return true;
    }
    if (input.incrementToken()) {
        if (/* condition */) {
           extraTokens.add("fo");
           savedState = captureState();
        }
        return true;
    }
    return false;
}

这是否意味着,对于空格标记化字符串 "a b c" 的输入流

 (a) -> (b) -> (c) -> ...

其中bbb 的新同义词,当使用restoreState 时,图将这样构造?

    (a)
   /   \
(b)    (bb)
   \   /
    (c)
     |
    ...

2。属性

鉴于文本foo bar bazfofoo 的词干和quxbar baz 的同义词,我是否构建了正确的属性表?

+--------+---------------+-----------+--------------+-----------+
|  Term  |  startOffset  | endOffset | posIncrement | posLenght |
+--------+---------------+-----------+--------------+-----------+
|  foo   |       0       |     3     |      1       |     1     |
|  fo    |       0       |     3     |      0       |     1     |
|  qux   |       4       |     11    |      0       |     2     |
|  bar   |       4       |     7     |      1       |     1     |
|  baz   |       8       |     11    |      1       |     1     |
+--------+---------------+-----------+--------------+-----------+

【问题讨论】:

  • 答案是:是的!!! :-) :-)

标签: java solr lucene token solr4


【解决方案1】:

1.

基于属性的 API 的工作原理是,分析器链中的每个 TokenStream 在每次调用 incrementToken() 时都会以某种方式修改某些 Attributes 的状态。然后链中的最后一个元素产生最终的标记。

每当您的分析器链的客户端调用incrementToken() 时,最后一个TokenStream 会将某些Attributes 的状态设置为表示下一个令牌所需的任何值。如果它不能这样做,它可以在其输入上调用incrementToken(),让之前的TokenStream 完成它的工作。这种情况一直持续到最后一个TokenStream 返回false,表明没有更多的令牌可用。

captureState 将调用TokenStream 的所有Attributes 的状态复制到StaterestoreState 用之前捕获的任何内容覆盖每个Attribute 的状态(以论据)。

您的令牌过滤器的工作方式是,它将调用input.incrementToken(),因此之前的TokenStream 会将Attributes 的状态设置为下一个令牌。然后,如果您定义的条件成立(例如,termAtt 是“b”),它会将“bb”添加到堆栈中,将此状态保存在某处并返回 true,以便客户端可以使用令牌。在下一次调用incrementToken() 时,它不会使用input.incrementToken()。无论当前状态是什么,它都代表先前已使用的令牌。然后过滤器恢复状态,让一切都和以前一样,然后产生“bb”作为当前令牌并返回true,以便客户端可以消费令牌。只有在下一次调用时,它才会(再次)使用上一个过滤器中的下一个令牌。

这实际上不会产生你显示的图表,而是在"b"之后插入"bb",所以它真的

(a) -> (b) -> (bb) -> (c)

那么,为什么首先要保存状态? 生成令牌时,您要确保,例如短语查询或突出显示将正常工作。当文本 "a b c""bb""b" 的同义词时,您会期望短语查询 "b c""bb c" 可以工作。你必须告诉索引,“b”和“bb”都在同一个位置。 Lucene 为此使用位置增量,默认情况下,位置增量为 1,这意味着每个新标记(读取,incrementToken() 的调用)在前一个标记之后出现 1 个位置。因此,对于最终位置,生产流是

(a:1) -> (b:2) -> (bb:3) -> (c:4)

当你真正想要的时候

(a:1) — -> (b:2)  -> — (c:3)
      \              /
        -> (bb:2) ->

因此,为了让您的过滤器生成图表,您必须将插入的 "bb" 的位置增量设置为 0

private final PositionIncrementAttribute posIncAtt = addAttribute(PositionIncrementAttribute.class);
// later in incrementToken
restoreState(savedState);
posIncAtt.setPositionIncrement(0);
termAtt.setEmpty().append(extraTokens.remove());

restoreState 确保保留其他属性,如偏移量、令牌类型等,您只需更改用例所需的属性。 是的,您正在覆盖restoreState 之前的任何状态,因此您有责任在正确的位置使用它。而且只要你不调用input.incrementToken(),你就不会推进输入流,所以你可以对状态做任何你想做的事情。

2.

词干分析器仅更改标记,它通常不会生成新标记,也不会更改位置增量或偏移量。 此外,作为位置增量意味着,当前术语应该在前一个标记之后出现positionIncrement 位置,您应该拥有增量为 1 的 qux,因为它是在 ofbar 之后的下一个标记增量为 0,因为它与 qux 处于相同位置。该表宁愿看起来像

+--------+---------------+-----------+--------------+-----------+
|  Term  |  startOffset  | endOffset | posIncrement | posLenght |
+--------+---------------+-----------+--------------+-----------+
|  fo    |       0       |     3     |      1       |     1     |
|  qux   |       4       |     11    |      1       |     2     |
|  bar   |       4       |     7     |      0       |     1     |
|  baz   |       8       |     11    |      1       |     1     |
+--------+---------------+-----------+--------------+-----------+

作为基本规则,对于多术语同义词,其中“ABC”是“a b c”的同义词,您应该看到,

  • positionIncrement("ABC") > 0(第一个记号的增量)
  • positionIncrement(*) >= 0(位置不得倒退)
  • startOffset("ABC") == startOffset("a") 和 endOffset("ABC") == endOffset("c")
    • 实际上,位于相同(start|end)位置的标记必须具有相同的(start|end)偏移量

希望这有助于阐明一些观点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-10
    • 2018-05-09
    • 1970-01-01
    • 2021-07-14
    • 2021-01-17
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多