将标记添加到lucene令牌流

Joh*_*erg 11 java lucene solr token solr4

我写了一个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;
}
Run Code Online (Sandbox Code Playgroud)

这是否意味着,对于空白标记化字符串的输入流 "a b c"

 (a) -> (b) -> (c) -> ...
Run Code Online (Sandbox Code Playgroud)

在哪里bb使用新的同义词b,使用时图形将如此构造restoreState

    (a)
   /   \
(b)    (bb)
   \   /
    (c)
     |
    ...
Run Code Online (Sandbox Code Playgroud)

2.属性

鉴于文本foo bar bazfo存在的茎fooqux是同义词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     |
+--------+---------------+-----------+--------------+-----------+
Run Code Online (Sandbox Code Playgroud)

knu*_*ker 21

1.

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

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

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

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

这实际上不会产生你显示的图形,而是插入"bb""b",所以它确实如此

(a) -> (b) -> (bb) -> (c)
Run Code Online (Sandbox Code Playgroud)

那么,你为什么要首先拯救国家?在生成令牌时,您需要确保,例如短语查询或突出显示将正常工作.如果您有文本"a b c"并且"bb"是同义词"b",那么您希望短语查询"b c"能够正常工作,以及"bb c".你必须告诉索引,"b"和"bb"都处于相同的位置.Lucene使用位置增量,默认情况下,位置增量为1,这意味着每个新标记(读取,调用incrementToken())在前一个标记之后的1个位置.因此,对于最终位置,产生流是

(a:1) -> (b:2) -> (bb:3) -> (c:4)
Run Code Online (Sandbox Code Playgroud)

而你真的想要

(a:1) — -> (b:2)  -> — (c:3)
      \              /
        -> (bb:2) ->
Run Code Online (Sandbox Code Playgroud)

因此,对于生成图形的过滤器,必须将插入的位置增量设置为0 "bb"

private final PositionIncrementAttribute posIncAtt = addAttribute(PositionIncrementAttribute.class);
// later in incrementToken
restoreState(savedState);
posIncAtt.setPositionIncrement(0);
termAtt.setEmpty().append(extraTokens.remove());
Run Code Online (Sandbox Code Playgroud)

restoreState确保,其他属性,如偏移,令牌类型等被保存,你只需要改变的,所需要的您的使用案例.是的,你要覆盖以前的状态restoreState,所以你有责任在正确的地方使用它.只要你不打电话input.incrementToken(),你就不会推进输入流,所以你可以用状态做任何你想做的事情.

2.

词干分析器仅更改令牌,它通常不会生成新令牌,也不会更改位置增量或偏移量.此外,由于位置增量意味着当前术语应该positionIncrement位于前一个令牌之后的位置qux,因此它应该具有增量1,因为它是之后的下一个令牌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     |
+--------+---------------+-----------+--------------+-----------+
Run Code Online (Sandbox Code Playgroud)

作为一个基本规则,对于多项同义词,"ABC"是"ab c"的同义词,你应该看到,

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

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