12

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

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

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

这大致就是我所做的

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) -> ...

bb新的同义词b在哪里restoreState

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

2. 属性

鉴于作为词干和同义词的文本foo bar baz,我是否构建了正确的属性表?fofooquxbar 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     |
+--------+---------------+-----------+--------------+-----------+
4

1 回答 1

22

1.

基于属性的 API 的工作原理是,TokenStream分析器链中的每一个都以某种方式Attribute在每次调用incrementToken(). 然后链中的最后一个元素产生最终的令牌。

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

A将调用captureState的所有 s 的状态复制到 a中,a用之前捕获的任何内容覆盖每个s 的状态(作为参数给出)。AttributeTokenStreamStaterestoreStateAttribute

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

这实际上不会产生您显示的图形,而是插入"bb"after "b",所以它真的

(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) ->

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

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位于前一个标记之后的位置,您应该具有qux1 的增量,因为它是之后的下一个标记,of并且bar应该具有 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”是“ab c”的同义词,您应该看到,

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

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

于 2013-11-19T19:44:15.957 回答