Dodawanie tokenów do strumienia tokenów lucene

Napisałem TokenFilter, który dodaje tokeny w strumieniu.

1. Testy pokazują, że działa, ale nie do końca rozumiem dlaczego.

Gdyby ktoś mógł rzucić światło na semantykę byłbym wdzięczny. W szczególności, przy (*), przywracaniu stanu, czy to nie znaczy, że albo nadpisujemy bieżący token, albo token utworzony przed przechwyceniem stanu?

To jest mniej więcej to, co zrobiłem

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;
}

Czy to oznacza, że dla strumienia wejściowego z tekstami znakowanymi białymi znakami "a b c"

 (a) -> (b) -> (c) -> ...

Gdzie bb jest nowym synonimem b, że wykres będzie skonstruowany w ten sposób, gdy restoreState zostanie użyty?

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

2. Atrybuty

Biorąc pod uwagę tekst foo bar baz z fo będącymi rdzeniem foo i qux będącymi synonimem bar baz, czy skonstruowałem poprawną tabelę atrybutów?

+--------+---------------+-----------+--------------+-----------+
|  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     |
+--------+---------------+-----------+--------------+-----------+
Author: Johan Sjöberg, 2013-07-04

1 answers

1.

Jak działa API oparte na atrybutach, to każde TokenStream w Twoim łańcuchu analizatorów modyfikuje w jakiś sposób stan niektórych Attribute s przy każdym wywołaniu incrementToken(). Ostatni element w Twoim łańcuchu wytwarza ostateczne tokeny.

Za każdym razem, gdy klient Twojego łańcucha analizatora wywoła incrementToken(), Ostatni TokenStream ustawi stan niektórych Attribute na to, co jest konieczne do reprezentowania następnego tokena. Jeśli nie jest w stanie tego zrobić, może wywołać incrementToken() na swoim wejściu, aby pozwolić poprzedni Wykonaj swoją pracę. Trwa to do ostatniego TokenStream zwraca false, wskazując, że nie ma już dostępnych tokenów.

A captureState kopiuje stan wszystkich Attributes wywołania TokenStream do a State, a restoreState nadpisuje każdy stan Attribute z tym, co zostało przechwycone wcześniej (jest podane jako argument).

Sposób działania filtra tokenów polega na wywołaniu input.incrementToken(), tak że poprzedni TokenStream ustawi stan Attributena następny token. Następnie, jeśli twój określony warunek przechowuje (powiedzmy, terminat to "b"), dodaje "bb" do stosu, zapisuje ten stan gdzieś i zwraca true, tak aby klient mógł wykorzystać token. Przy następnym wywołaniu incrementToken(), nie użyje input.incrementToken(). Jakikolwiek jest obecny stan, reprezentuje poprzedni, już zużyty token. Następnie filtr przywraca stan tak, że wszystko jest dokładnie takie, jak było wcześniej, a następnie wytwarza "bb" jako bieżący token i zwraca true, tak że klient może wykorzystać token. Tylko przy następnym telefonie, to będzie (ponownie) zużywał następny token z poprzedniego filtra.

To nie wyświetli wyświetlanego wykresu, ale Wstaw "bb" po "b", więc to naprawdę

(a) -> (b) -> (bb) -> (c)
Więc dlaczego w ogóle ratujesz Państwo? Produkując tokeny, chcesz mieć pewność, że np. zapytania fraz lub podświetlanie będą działać poprawnie. Jeśli masz tekst "a b c" i "bb" jest synonimem "b", możesz oczekiwać, że zapytanie frazy "b c" zadziała, podobnie jak "bb c". Musisz powiedz indeksowi, że zarówno "b", jak i " bb " znajdują się w tej samej pozycji. Lucene używa w tym celu przyrostu pozycji i domyślnie przyrost pozycji wynosi 1, co oznacza, że każdy nowy token (odczyt, wywołanie incrementToken()) pojawia się o 1 pozycję po poprzednim. Tak więc, z końcowymi pozycjami, wytwarzany strumień wynosi
(a:1) -> (b:2) -> (bb:3) -> (c:4)

While you actually want

(a:1) — -> (b:2)  -> — (c:3)
      \              /
        -> (bb:2) ->

Tak więc, aby twój filtr mógł wygenerować wykres, musisz ustawić przyrost pozycji na 0 dla wstawionego "bb"

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

The restoreState upewnia się, że inne atrybuty, takie jak offsety, typy tokenów, itp. są zachowane i musisz tylko zmienić te, które są wymagane dla Twojego przypadku użycia. Tak, nadpisujesz stan, który był tam wcześniej restoreState, więc twoim obowiązkiem jest użycie go we właściwym miejscu. I dopóki nie zadzwonisz input.incrementToken(), nie przyspieszysz strumienia wejściowego, więc możesz robić, co chcesz ze stanem.

2.

Stemmer zmienia tylko token, Zwykle nie wytwarza nowych tokenów ani nie zmienia przyrostu pozycji ani przesunięć. Ponadto, ponieważ przyrost pozycji oznacza, że bieżący termin powinien pochodzić positionIncrement pozycje po poprzednim tokenie, powinieneś mieć qux z przyrostem 1, ponieważ jest to następny token po of i bar powinien mieć przyrost 0, ponieważ znajduje się w tej samej pozycji co qux. Tabela wygląda raczej tak:

+--------+---------------+-----------+--------------+-----------+
|  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     |
+--------+---------------+-----------+--------------+-----------+

Jako podstawowa zasada, dla synonimów wieloterminowych, gdzie " ABC "jest synonimem" a b c", powinieneś zobaczyć, że

    W ten sposób można uzyskać więcej informacji na ten temat.]}
  • positionIncrement (*) > = 0 (pozycje nie mogą się cofać)
  • startOffset ("ABC") = = startOffset ("a") i endOffset ("ABC") = = endOffset ("c")
    • w rzeczywistości tokeny na tej samej pozycji (początek|koniec) muszą mieć takie samo (początek|koniec) przesunięcie

Mam nadzieję, że to pomoże rzucić trochę światła.

 20
Author: knutwalker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-19 19:44:15