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.

С помощью WhitespaceTokenizerFactorySolr разделит вашу строку запроса на слова.

Но после токенизации вы (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>
Другие вопросы по тегам