#java #solr #lucene
#java #solr #lucene
Вопрос:
Мы пытаемся реализовать пользовательский фильтр, который должен запоминать прошлые токены, которые были обработаны ранее в рамках того же запроса. Мы попытались переопределить методы end()
and / or reset()
из TokenFilter
, но обнаружили, что эти методы вызывались между каждым токеном.
Это противоречило нашим ожиданиям end()
, что методы and / or reset()
будут вызываться только в начале или конце потока токенов, представляющего запрос. Это неожиданное поведение может быть воспроизведено следующим примером кода ниже.
(solr) фрагмент схемы:
<fieldType name="text_general" class="solr.TextField">
<analyzer type="index">
...
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="com.foobar.solr.CustomFilterFactory" />
</analyzer>
</fieldType>
Реализация фильтра:
public class CustomFilter extends TokenFilter {
CharTermAttribute termAttribute = addAttribute(CharTermAttribute.class);
public CustomFilter(TokenStream in) {
super(in);
}
@Override
public boolean incrementToken() throws IOException {
System.out.println("### increment token pre loop: " termAttribute.toString());
while (input.incrementToken()) {
System.out.println("### increment token looping through input: " termAttribute.toString());
}
return false;
}
@Override
public void end() throws IOException {
System.out.println("### end");
super.end();
}
@Override
public void reset() throws IOException {
System.out.println("### reset");
super.reset();
}
}
Вывод журнала для запроса «foo bar»:
### reset
### increment token pre loop:
### increment token looping through input: foo
### end
### reset
### increment token pre loop:
### increment token looping through input: bar
### end
Почему методы end()
and reset()
вызываются для каждого токена, а не для полного запроса?
Редактировать: или почему input.incrementToken()
возвращается false
после обработки первого токена?
Комментарии:
1. В javadocs для этих методов четко указано, что они вызываются до и после каждого токена.
2. Не уверен, какой javadoc вы имеете в виду: javadoc for
TokenStream.end()
заявляет: «Этот метод вызывается потребителем после того, как был использован последний токен, после того, как {@link #incrementToken()} вернул <code>false</code> »3. вы используете анализатор запросов или создаете свои запросы с помощью кода?
4. @omu_negru Для этого теста мы используем анализатор запросов, который является частью консоли администратора Solr. Solr выполняется локально.
Ответ №1:
Поскольку я заметил, что вы используете solr, вам нужно понимать, что анализатор запросов будет разбивать запрос на пробелы, и он имеет приоритет перед вашим анализатором: поэтому, если вы запрашиваете «foo bar», у вас будут «foo» и «bar», передаваемые отдельно по цепочке анализаторов. Вы можете обойти это поведение, сделав «foo bar» запросом фразы, добавив "foo bar"
РЕДАКТИРОВАТЬ: для пояснения, запрос фразы будет иметь приоритет над разделением пробелов анализатора запросов и определяется путем обертывания последовательности токенов внутри символов кавычек
Комментарии:
1. Спасибо, это объясняет. В качестве дополнительного примечания (поскольку запросы фраз не будут работать для нас), есть идеи, как мы могли бы определить, что токен поступает из нового или Другого (т. Е. параллельного) запроса?
2. не совсем, но я очень сомневаюсь, что ваши токенизаторы или фильтры используются из нескольких потоков, поскольку они могут переносить состояние (и некоторые из них это делают), и ни один из них не кажется мне особенно потокобезопасным. Я бы поставил свою ставку на написание собственного класса анализатора и выполнение своих задач внутри
createComponents
метода.