将标记添加到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) -> ... 

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

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

2.属性

鉴于文本foo bar baz其中fofoo的词干,而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 | +--------+---------------+-----------+--------------+-----------+ 

1。

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

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

captureState将调用TokenStream的所有Attribute的状态复制到一个StaterestoreState用之前捕获的任何内容覆盖每个Attribute的状态(作为参数给出)。

令牌filter的工作方式是,它将调用input.incrementToken() ,以便前一个TokenStreamAttribute 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”)
    • 实际上,相同(开始|结束)位置的标记必须具有相同(开始|结束)偏移

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