gpt4 book ai didi

java - 将 token 添加到 lucene token 流

转载 作者:搜寻专家 更新时间:2023-10-30 21:19:58 27 4
gpt4 key购买 nike

我写了一个 TokenFilter在流中添加 token 。

1. 测试表明它有效,但我不完全明白为什么。

如果有人能阐明语义,我将不胜感激。特别是,在 (*) ,恢复状态,是不是意味着我们要么覆盖当前 token ,要么覆盖捕获状态之前创建的 token ?

这大致是我所做的

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 bazfofoo 的词干和 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 的工作原理是,每个 TokenStream在您的分析器链中以某种方式修改了某些 Attribute 的状态每次拨打 incrementToken() .然后链中的最后一个元素产生最终的 token 。

每当您的分析器链的客户端调用 incrementToken() ,最后TokenStream会设置一些 Attribute 的状态s 代表下一个标记所需的任何东西。如无法办理,可调用incrementToken()在其输入上,让前一个 TokenStream做它的工作。这一直持续到最后 TokenStream返回 false ,表示没有更多的 token 可用。

一个 captureState复制所有状态 Attribute电话号码 TokenStreamState , restoreState覆盖每个 Attribute的状态与之前捕获的任何内容(作为参数给出)。

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

这实际上不会生成您显示的图形,而是插入 "bb"之后 "b" ,所以它真的

(a) -> (b) -> (bb) -> (c)

那么,为什么首先要保存状态?
在生产 token 时,您要确保,例如短语查询或突出显示将正常工作。当您收到文本 "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确保保留其他属性,如偏移量、 token 类型等,您只需更改用例所需的属性。
是的,您正在覆盖之前的任何状态 restoreState ,因此您有责任在正确的地方使用它。只要你不打电话 input.incrementToken() ,你不推进输入流,所以你可以对状态做任何你想做的事情。

2.

词干分析器只更改 token ,它通常不会产生新的 token ,也不会更改位置增量或偏移量。
此外,作为位置增量意味着,当前术语应该是 positionIncrement在前一个 token 之后的位置,您应该有 qux增量为 1,因为它是 of 之后的下一个标记和 bar应该有 0 的增量,因为它与 qux 的位置相同. table 宁愿看起来像
+--------+---------------+-----------+--------------+-----------+
| 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”是“a b c”的同义词,您应该看到,
  • positionIncrement("ABC") > 0(第一个标记的增量)
  • positionIncrement(*) >= 0(仓位不能倒退)
  • startOffset("ABC") == startOffset("a") 和 endOffset("ABC") == endOffset("c")
  • 实际上,相同(开始|结束)位置的标记必须具有相同的(开始|结束)偏移

  • 希望这有助于阐明一些情况。

    关于java - 将 token 添加到 lucene token 流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17476674/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com