Solr Dismax handler - пробел и поведение специальных символов
У меня странные результаты, когда в моем запросе есть специальные символы.
Вот моя просьба:
q=histoire-france&start=0&rows=10&sort=score+desc&defType=dismax&qf=any^1.0&mm=100%
Разобранный запрос:
<str name="parsedquery_toString">+((any:histoir any:franc)) ()</str>
У меня 17000 результатов, потому что Solr делает OR (должно быть AND).
У меня нет проблем, когда я использую пробел вместо специального символа:
q=histoire france&start=0&rows=10&sort=score+desc&defType=dismax&qf=any^1.0&mm=100%
<str name="parsedquery_toString">+(((any:histoir) (any:franc))~2) ()</str>
2000 результатов по этому запросу.
Вот мой schema.xml (соответствующие части):
<fieldType name="text" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" preserveOriginal="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.CommonGramsFilterFactory" words="stopwords_french.txt" ignoreCase="true"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords_french.txt" enablePositionIncrements="true"/>
<filter class="solr.SnowballPorterFilterFactory" language="French" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
<filter class="solr.ASCIIFoldingFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<!--<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>-->
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1" preserveOriginal="0"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.CommonGramsFilterFactory" words="stopwords_french.txt" ignoreCase="true"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords_french.txt" enablePositionIncrements="true"/>
<filter class="solr.SnowballPorterFilterFactory" language="French" protected="protwords.txt"/>
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
<filter class="solr.ASCIIFoldingFilterFactory"/>
</analyzer>
</fieldType>
Я даже пытался с PatternTokenizerFactory токенизировать на пробелах и специальных символах, но без изменений...
Мой текущий обходной путь - заменить все специальные символы пробелами перед отправкой запроса в Solr, но это не удовлетворяет.
РЕДАКТИРОВАТЬ: Даже с charFilter (PatternReplaceCharFilterFactory), чтобы заменить специальные символы пробелами, это не работает...
Первая строка анализа через solr admin, с подробным выводом, для запроса = 'histoire-france':
org.apache.solr.analysis.PatternReplaceCharFilterFactory {replacement= , pattern=([,;./\\'&-]), luceneMatchVersion=LUCENE_32}
text histoire france
'-' заменяется на '', затем токенизируется WhitespaceTokenizerFactory. Тем не менее, у меня все еще разное количество результатов для "histoire-france" и "histoire france".
Я что-то пропустил?
4 ответа
Это была ошибка: https://issues.apache.org/jira/browse/SOLR-3589
Если для edismax mm задано значение 100%, если один из токенов разделен на два токена цепью анализатора (т. Е. "Fire-fly" => fire fly), параметр mm игнорируется и эквивалент запроса OR для "fire OR fly" " производится. Это особенно проблема для языков, которые не используют пробелы для разделения слов, таких как китайский или японский.
Это исправлено в Solr 4.1 (22 января 2013 г.)
Вы получаете различное количество результатов поиска по "histoire-france" и "histoire france", потому что синтаксический анализатор запросов создает запрос фразы в первом случае и логический запрос (разделяет два слова) во втором случае.
Это неочевидное поведение imho, но я считаю, что трудно удовлетворить все варианты использования.
Чтобы сделать поиск, считающий "histoire-france" просто двумя словами, вы можете добавить " solr.PositionFilterFactory" в конец анализатора запросов, например:
<analyzer type="query">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.PositionFilterFactory" />
</analyzer>
Тогда результаты поиска для "histoire-france" и "histoire france" будут равны.
Обратите внимание, что фильтр поиска позиции может быть нежелателен для поиска по фразе (должны присутствовать как "historyie", так и "france"). Вместо этого рассмотрите возможность использования параметра qs > 0 для запроса, если вы изменили последовательность терминов с помощью, скажем, фильтра NGram.
С помощью WhitespaceTokenizerFactory
Solr разделит вашу строку запроса на слова.
Но после токенизации вы (Solr) разделите свое слово (снова) на термины, используя solr.WordDelimiterFilterFactory. Посмотрите документацию и посмотрите пример Wi-Fi.
Это может быть одной из причин, почему histoire france
а также histoire-france
обрабатываются по-разному.
2-й: не забывайте, что DSIMAX обрабатывает (обычно) запросный термин как "термин", а также (дополнительный) снова как анализируемую строку.
Чтобы решить вашу проблему, вы можете попытаться избежать разделителя мира и попытаться обработать "токенизацию" с помощью PatternTokenizerFactory
(как вы пытались раньше, но теперь без WordDelimiterFilterFactory).
Если это не сработает, попробуйте опубликовать полный вывод файла analysys.jsp
Включите autoGeneratePhraseQueries в true, и это сгенерирует запросы фраз.
Таким образом, при поиске по histoire-franc он генерирует запрос с кавычками, который включает только документы, содержащие оба слова в качестве сопоставляемой фразы.
<str name="parsedquery">(+DisjunctionMaxQuery(((any:histoire any:franc))))/no_coord</str>
Пример рабочей конфигурации -
<fieldType name="text_test" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
Используйте запрос slop для указания количества отказов, например qs=10
во фразе запроса.
<str name="parsedquery">(+DisjunctionMaxQuery((any:"histoire france"~10)))/no_coord</str>