12

TokenFilterストリームにトークンを追加するを書きました。

1. テストでは機能することが示されていますが、その理由が完全にはわかりません。

誰かがセマンティクスに光を当てることができれば、私は感謝しています。特に、 で(*)状態を復元するということは、現在のトークンまたは状態をキャプチャする前に作成されたトークンを上書きするということではないでしょうか。

これは大体私がやったことです

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の新しい同義語はどこですか?brestoreState

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

2.属性

の語幹であり、同義語であるというテキストfoo bar bazが与えられた場合、正しい属性テーブルを作成しましたか?fofooquxbar 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     |
+--------+---------------+-----------+--------------+-----------+
4

1 に答える 1

22

1.

属性ベースの API がどのように機能するかというとTokenStream、アナライザー チェーン内のAttributeすべての が、 の呼び出しごとにいくつかの の状態を変更しますincrementToken()。次に、チェーンの最後の要素が最終的なトークンを生成します。

アナライザー チェーンのクライアントが を呼び出すときはいつでも、incrementToken()最後に、次のトークンを表すために必要なものTokenStreamにいくつかの の状態を設定します。Attributeそれができない場合はincrementToken()、その入力を呼び出して、前の作業に任せることができTokenStreamます。これは、最後のTokenStreamが返されるまで続き、これfalse以上トークンが利用できないことを示します。

Aは呼び出しcaptureStateのすべての の状態を a にコピーし、aはすべての状態を以前にキャプチャされたもの (引数として指定) で上書きします。AttributeTokenStreamStaterestoreStateAttribute

トークン フィルターが機能する方法は、 を呼び出すinput.incrementToken()ため、前のトークンはs の状態を次のトークンにTokenStream設定します。Attribute次に、定義された条件が成立する場合 (たとえば、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) ->

したがって、フィルターがグラフを生成するには、挿入された位置の増分を 0 に設定する必要があります。"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 にofbar、同じ位置にあるため増分を 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」が「ab c」の同義語である多項同義語の場合、次のようになります。

  • positionIncrement("ABC") > 0 (最初のトークンの増分)
  • positionIncrement(*) >= 0 (位置が逆になってはいけません)
  • startOffset("ABC") == startOffset("a") および endOffset("ABC") == endOffset("c")
    • 実際には、同じ (開始|終了) 位置にあるトークンは、同じ (開始|終了) オフセットを持つ必要があります

これが光を当てるのに役立つことを願っています。

于 2013-11-19T19:44:15.957 に答える