我写了一个TokenFilter
,它在流中添加了令牌。
如果有人可以阐明语义,我将不胜感激。特别是,在(*)
恢复状态,这是否意味着我们要么覆盖当前令牌,要么在捕获状态之前创建令牌?
这大致就是我所做的
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)
|
...
鉴于文本foo bar baz
fo
是foo
和qux
的词干是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 |
+--------+---------------+-----------+--------------+-----------+
答案 0 :(得分:21)
<强> 1 强>
基于属性的API的工作原理是,每次调用TokenStream
时,分析器链中的每个Attribute
都会以某种方式修改某些incrementToken()
的状态。链中的最后一个元素然后生成最终的标记。
每当分析器链的客户端调用incrementToken()
时,最后TokenStream
会将某些Attribute
的状态设置为表示下一个令牌所需的任何内容。如果无法执行此操作,则可以在其输入上调用incrementToken()
,让之前的TokenStream
执行其工作。这一直持续到最后TokenStream
返回false
,表示没有更多令牌可用。
captureState
将调用Attribute
的所有TokenStream
状态复制为State
,restoreState
覆盖每Attribute
个' s状态与之前捕获的任何东西(作为参数给出)。
令牌过滤器的工作方式是,它会调用input.incrementToken()
,以便之前的TokenStream
将Attribute
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"
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”的同义词,你应该看到,
希望这有助于揭示一些亮点。