Ответ 1
1.
Как работает API на основе атрибутов, каждый TokenStream
в цепочке анализатора каким-то образом изменяет состояние некоторого Attribute
при каждом вызове incrementToken()
. Последний элемент в вашей цепочке затем выдает финальные токены.
Всякий раз, когда клиент вашей цепи анализатора вызывает incrementToken()
, последний TokenStream
будет устанавливать состояние некоторого Attribute
на все, что необходимо для представления следующего токена. Если он не может этого сделать, он может называть incrementToken()
на своем входе, чтобы предыдущий TokenStream
выполнял свою работу. Это продолжается до тех пор, пока последний TokenStream
не вернет false
, указывая, что больше нет токенов.
A captureState
копирует состояние всех Attribute
вызывающего TokenStream
в State
, a restoreState
перезаписывает каждое состояние Attribute
тем, что было ранее (указано в качестве аргумента).
Как работает ваш токен-фильтр, он вызовет input.incrementToken()
, так что предыдущий TokenStream
установит состояние Attribute
s 'в качестве следующего токена. Затем, если ваше определенное условие выполнено (например, терминAtt является "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, поскольку это следующий токен после 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" является синонимом "a b c", вы должны видеть, что
- positionIncrement ( "ABC" ) > 0 (приращение первого токена)
- positionIncrement (*) >= 0 (позиции не должны возвращаться назад)
- startOffset ( "ABC" ) == startOffset ( "a" ) и endOffset ( "ABC" ) == endOffset ( "c" )
- Фактически, токены в одной и той же позиции (начало | конец) должны иметь одинаковый (начальный | конец) смещение
Надеюсь, это поможет пролить свет.