将标记添加到lucene令牌流

时间:2013-07-04 18:54:26

标签: java solr lucene token solr4

我写了一个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) -> ...

其中bbb的新同义词,在使用restoreState时,图表的构造方式是这样的吗?

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

2。属性

鉴于文本foo bar baz fofooqux的词干是bar baz的同义词,我是否构建了正确的属性表?< / p>

+--------+---------------+-----------+--------------+-----------+
|  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     |
+--------+---------------+-----------+--------------+-----------+

1 个答案:

答案 0 :(得分:21)

<强> 1

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

每当分析器链的客户端调用incrementToken()时,最后TokenStream会将某些Attribute的状态设置为表示下一个令牌所需的任何内容。如果无法执行此操作,则可以在其输入上调用incrementToken(),让之前的TokenStream执行其工作。这一直持续到最后TokenStream返回false,表示没有更多令牌可用。

captureState将调用Attribute的所有TokenStream状态复制为StaterestoreState覆盖每Attribute个' s状态与之前捕获的任何东西(作为参数给出)。

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

这实际上不会生成您显示的图表,而是在"bb"之后插入"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) ->

因此,要使您的过滤器生成图形,您必须将插入的"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位置,因此您应该qux增加1,因为它是{{1}之后的下一个令牌}和of的增量应为0,因为它与bar位于同一位置。该表看起来像

qux

作为一项基本规则,对于多项同义词,“ABC”是“a b c”的同义词,你应该看到,

  • positionIncrement(“ABC”)&gt; 0(第一个标记的增量)
  • positionIncrement(*)&gt; = 0(位置不得倒退)
  • startOffset(“ABC”)== startOffset(“a”)和endOffset(“ABC”)== endOffset(“c”)
    • 实际上,相同(开始|结束)位置的标记必须具有相同的(开始|结束)偏移

希望这有助于揭示一些亮点。