将标记添加到lucene令牌流
我写了一个TokenFilter
,它在一个流中添加了令牌。
1.测试显示它有效,但我不完全理解为什么。
如果有人能够阐明语义,我将不胜感激。 特别是在(*)
,恢复状态,这是否意味着我们要么覆盖当前令牌,要么在捕获状态之前创建令牌?
这大致就是我所做的
private final LinkedList extraTokens = new LinkedList(); 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; }
这是否意味着,对于空白标记化字符串"abc"
的输入流
(a) -> (b) -> (c) -> ...
其中bb
是b
的新同义词,当使用restoreState
时,图形将像这样构造?
(a) / \ (b) (bb) \ / (c) | ...
2.属性
鉴于文本foo bar baz
其中fo
是foo
的词干,而qux
是bar 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 | +--------+---------------+-----------+--------------+-----------+
1。
基于属性的API的工作原理是,每次调用incrementToken()
分析器链中的每个TokenStream
都会以某种方式修改某些Attribute
的状态。 链中的最后一个元素然后生成最终的标记。
只要分析器链的客户端调用incrementToken()
,最后一个TokenStream
就会将某些Attribute
的状态设置为表示下一个令牌所需的任何值。 如果它不能这样做,它可以在其输入上调用incrementToken()
,让前一个TokenStream
完成它的工作。 这一直持续到最后一个TokenStream
返回false
,表明没有更多的令牌可用。
captureState
将调用TokenStream
的所有Attribute
的状态复制到一个State
, restoreState
用之前捕获的任何内容覆盖每个Attribute
的状态(作为参数给出)。
令牌filter的工作方式是,它将调用input.incrementToken()
,以便前一个TokenStream
将Attribute
s’状态设置为下一个令牌。 然后,如果您定义的条件成立(例如,termAtt是“b”),它会将“bb”添加到堆栈,将此状态保存在某处并返回true,以便客户端可以使用该令牌。 在下一次调用incrementToken()
,它不会使用input.incrementToken()
。 无论当前状态如何,它都代表先前已经消耗的令牌。 然后,filter恢复状态,以便一切都与之前完全一样,然后生成“bb”作为当前令牌并返回true,以便客户端可以使用令牌。 只有在下次调用时,它才会(再次)使用前一个filter中的下一个标记。
这实际上不会产生你显示的图形,但在"b"
之后插入"bb"
"b"
,所以它确实如此
(a) -> (b) -> (bb) -> (c)
那么,你为什么要首先拯救国家呢? 在生成令牌时,您需要确保,例如短语查询或突出显示将正常工作。 当你有文本"abc"
和"bb"
是"b"
的同义词时,你希望短语查询"bc"
起作用,以及"bb c"
。 你必须告诉索引,“b”和“bb”都处于相同的位置。 Lucene使用位置增量,默认情况下,位置增量为1,这意味着每个新标记(读取,调用incrementToken()
)都在前一个标记之后的1个位置。 因此,对于最终位置,产生流是
(a:1) -> (b:2) -> (bb:3) -> (c:4)
而你真的想要
(a:1) — -> (b:2) -> — (c:3) \ / -> (bb:2) ->
因此,对于生成图形的filter,必须将插入的"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
前一个令牌之后的positionIncrement
位置,因此它应该具有增量为1的qux
,因为它是之后的下一个标记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”是“abc”的同义词,你应该看到,
- positionIncrement(“ABC”)> 0(第一个标记的增量)
- positionIncrement(*)> = 0(位置不得倒退)
- startOffset(“ABC”)== startOffset(“a”)和endOffset(“ABC”)== endOffset(“c”)
- 实际上,相同(开始|结束)位置的标记必须具有相同(开始|结束)偏移
希望这有助于揭示一些亮点。