SOLR eDismax толерантность к опечаткам для фраз

Как можно построить запрос, который будет искать как точные фразы, так и фразы с опечатками? Я застрял на этом и похоже, что я двигаюсь в неправильном направлении.

Например, у меня есть следующее поле в моем запросе edismax:

q=apple iphone

Это работает, но теперь мне нужно сделать его более терпимым к опечаткам. Я обновляю свой запрос, и теперь он возвращает те же результаты, что и раньше, даже когда пользователь вводит ошибки:

q=aple~2 iphane~2

Далее я обнаружил, что теперь точное совпадение запроса не всегда находится на первой странице (например, у меня действительно есть продукт 'aple iphane'). Итак, я добавляю точный запрос, используя условие «ИЛИ». Теперь мой запрос выглядит так

q=(aple~2 iphane~2) OR 'aple iphane'^3

Проблема в том, что теперь он возвращает только точное совпадение и больше не возвращает нечеткие записи. Что я делаю неправильно?

Вот полный запрос:

http://localhost:8983/solr/test/select?omitHeader=true
&q=(aple~2 iphane~2) OR 'aple iphane'^3
&start=0
&rows=30
&fl=*,score
&fq=itemType:"Product"
&defType=edismax
&qf=title_de^1000 title_de_ranked^1000 description_de^1 category_name_de^50 brand^15 merchant_name^80 uniuque_values^10000 searchable_attribute_product.name^1000 searchable_attribute_product.description.short^100 searchable_attribute_product.description.long^100 searchable_attribute_mb.book.author^500
&mm=90
&pf=title_de^2000 description_de^2
&ps=1
&qs=2
&boost=category_boost
&mm.autoRelax=true
&wt=json
&json.nl=flat

У меня есть ошибка в запросе, или я выбрал совершенно неправильный способ?

Эту фразу я хочу найти в 'title_de', все остальные поля второстепенны. Вот тип поля из моей схемы:

<fieldType name="text_de_ngram" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_de.txt" />
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
        <filter class="solr.GermanNormalizationFilterFactory"/>
        <filter class="solr.GermanLightStemFilterFactory"/>
        <filter class="solr.NGramFilterFactory" minGramSize="2" maxGramSize="25"/>
    </analyzer>
    <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_de.txt" />
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/>
        <filter class="solr.GermanNormalizationFilterFactory"/>
        <filter class="solr.GermanLightStemFilterFactory"/>
        <filter class="solr.SnowballPorterFilterFactory" language="German" />
    </analyzer>
</fieldType>

Спасибо!


UPD: Я обнаружил, что мой запрос (q=(aple~2 iphane~2) ИЛИ 'aple iphane'^3) неверен, поэтому я нашел, как построить 2 других запроса, которые работают лучше, вы можете их увидеть в конце поста. Я до сих пор не знаю, почему они дают разные результаты, потому что оператором по умолчанию для запроса SOLR является «ИЛИ», поэтому «термин1 ИЛИ термин2 ИЛИ термин3 ИЛИ термин4» должен быть таким же, как «(термин1 ИЛИ термин2) ИЛИ (термин3 ИЛИ термин4).< /em>
По предложению @Persimmonium я добавляю несколько отладочных примеров, чтобы показать, как работают нечеткие запросы для edismax (но не всегда ожидаемые). Я обнаружил, что «apple iphone» — не лучший пример в моем большом и немецком языковом индексе, поэтому я использовал в качестве примера продукт с названием «Samsung Magic Info-Lite».

Вот все параметры моего запроса:

"params":{
      "mm":"100%",
      "q":"samsung magic",
      "defType":"edismax",
      "indent":"on",
      "qf":"title_de",
      "fl":"*,score",
      "pf":"title_de",
      "wt":"json",
      "debugQuery":"on",
      "_":"1501409530601"
}

Итак, этот запрос возвращает мне правильные продукты (у меня есть 6 продуктов с обоими этими словами в поле title_de). После того, как я добавлю опечатки к обоим словам:

"q":"somsung majic"

Товары не найдены.

Затем я добавляю нечеткие операторы к обоим словам:

"q":"somsung~2 majic~2"

Найдено 6 товаров. Вот результат отладочного запроса:

"debug":{
      "rawquerystring":"somsung~2 majic~2",
      "querystring":"somsung~2 majic~2",
      "parsedquery":"(+(DisjunctionMaxQuery((title_de:somsung~2)) DisjunctionMaxQuery((title_de:majic~2)))~2 DisjunctionMaxQuery((title_de:\"somsung 2 majic 2\")))/no_coord",
      "parsedquery_toString":"+(((title_de:somsung~2) (title_de:majic~2))~2) (title_de:\"somsung 2 majic 2\")",
      "explain":{
            "69019":"\n1.3424492 = sum of:\n  1.3424492 = sum of:\n    1.1036766 = sum of:\n      0.26367697 = weight(title_de:amsung in 305456) [ClassicSimilarity], result of:\n        0.26367697 = score(doc=305456,freq=1.0), product of:\n          0.073149204 = queryWeight, product of:\n            0.6666666 = boost\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.015219777 = queryNorm\n          3.604646 = fieldWeight in 305456, product of:\n            1.0 = tf(freq=1.0), with freq of:\n              1.0 = termFreq=1.0\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.5 = fieldNorm(doc=305456)\n      0.2373093 = weight(title_de:msung in 305456) [ClassicSimilarity], result of:\n        0.2373093 = score(doc=305456,freq=1.0), product of:\n          0.06583429 = queryWeight, product of:\n            0.6 = boost\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.015219777 = queryNorm\n          3.604646 = fieldWeight in 305456, product of:\n            1.0 = tf(freq=1.0), with freq of:\n              1.0 = termFreq=1.0\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.5 = fieldNorm(doc=305456)\n      0.26367697 = weight(title_de:samsun in 305456) [ClassicSimilarity], result of:\n        0.26367697 = score(doc=305456,freq=1.0), product of:\n          0.073149204 = queryWeight, product of:\n            0.6666666 = boost\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.015219777 = queryNorm\n          3.604646 = fieldWeight in 305456, product of:\n            1.0 = tf(freq=1.0), with freq of:\n              1.0 = termFreq=1.0\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.5 = fieldNorm(doc=305456)\n      0.33901328 = weight(title_de:samsung in 305456) [ClassicSimilarity], result of:\n        0.33901328 = score(doc=305456,freq=1.0), product of:\n          0.094048984 = queryWeight, product of:\n            0.85714287 = boost\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.015219777 = queryNorm\n          3.604646 = fieldWeight in 305456, product of:\n            1.0 = tf(freq=1.0), with freq of:\n              1.0 = termFreq=1.0\n            7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              635.0 = docFreq\n              316313.0 = docCount\n            0.5 = fieldNorm(doc=305456)\n    0.23877257 = sum of:\n      0.23877257 = weight(title_de:magic in 305456) [ClassicSimilarity], result of:\n        0.23877257 = score(doc=305456,freq=1.0), product of:\n          0.0762529 = queryWeight, product of:\n            0.8 = boost\n            6.262649 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              1638.0 = docFreq\n              316313.0 = docCount\n            0.015219777 = queryNorm\n          3.1313245 = fieldWeight in 305456, product of:\n            1.0 = tf(freq=1.0), with freq of:\n              1.0 = termFreq=1.0\n            6.262649 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n              1638.0 = docFreq\n              316313.0 = docCount\n            0.5 = fieldNorm(doc=305456)\n",
      },
      "QParser":"ExtendedDismaxQParser"
}

Такое поведение меня устраивает, пока у меня нет реального продукта с названием Somsung majic. Это теоретическая ситуация, но на практике есть много других неверных результатов поиска, вызванных этими нечеткими операторами.

Итак, чтобы справиться с такими вещами, моя идея заключалась в том, как я описал изначально, чтобы добавить точную запись (без нечетких модификаторов) с повышающим коэффициентом. Итак, теперь вопрос, как это будет лучше реализовано. Я обнаружил, что этот запрос работает приемлемо, если я уменьшу параметр mm:

"q":"somsung~2 majic~2 somsung^3 majic^3"

Это потому, что я добавляю больше слов в запрос, поэтому «минимум должен совпадать» также необходимо уменьшить. Проблема в том, что при уменьшении «мм» я получаю плохие результаты для длинных заголовков с точным вводом заголовка (некоторые неправильные элементы могут быть оценены выше из-за других факторов). Это отладка для него:

"debug":{
      "rawquerystring":"somsung~2 majic~2 somsung^3 majic^3",
      "querystring":"somsung~2 majic~2 somsung^3 majic^3",
      "parsedquery":"(+(DisjunctionMaxQuery((title_de:somsung~2)) DisjunctionMaxQuery((title_de:majic~2)) DisjunctionMaxQuery((title_de:somsung))^3.0 DisjunctionMaxQuery((title_de:majic))^3.0)~2 DisjunctionMaxQuery((title_de:\"somsung 2 majic 2 somsung 3 majic 3\")))/no_coord",
      "parsedquery_toString":"+(((title_de:somsung~2) (title_de:majic~2) ((title_de:somsung))^3.0 ((title_de:majic))^3.0)~2) (title_de:\"somsung 2 majic 2 somsung 3 majic 3\")",
      "explain":{
            "69019":"\n0.3418829 = sum of:\n  0.3418829 = product of:\n    0.6837658 = sum of:\n      0.5621489 = sum of:\n        0.13430178 = weight(title_de:amsung in 305456) [ClassicSimilarity], result of:\n          0.13430178 = score(doc=305456,freq=1.0), product of:\n            0.037257966 = queryWeight, product of:\n              0.6666666 = boost\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.0077520725 = queryNorm\n            3.604646 = fieldWeight in 305456, product of:\n              1.0 = tf(freq=1.0), with freq of:\n                1.0 = termFreq=1.0\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.5 = fieldNorm(doc=305456)\n        0.12087161 = weight(title_de:msung in 305456) [ClassicSimilarity], result of:\n          0.12087161 = score(doc=305456,freq=1.0), product of:\n            0.033532172 = queryWeight, product of:\n              0.6 = boost\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.0077520725 = queryNorm\n            3.604646 = fieldWeight in 305456, product of:\n              1.0 = tf(freq=1.0), with freq of:\n                1.0 = termFreq=1.0\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.5 = fieldNorm(doc=305456)\n        0.13430178 = weight(title_de:samsun in 305456) [ClassicSimilarity], result of:\n          0.13430178 = score(doc=305456,freq=1.0), product of:\n            0.037257966 = queryWeight, product of:\n              0.6666666 = boost\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.0077520725 = queryNorm\n            3.604646 = fieldWeight in 305456, product of:\n              1.0 = tf(freq=1.0), with freq of:\n                1.0 = termFreq=1.0\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.5 = fieldNorm(doc=305456)\n        0.17267373 = weight(title_de:samsung in 305456) [ClassicSimilarity], result of:\n          0.17267373 = score(doc=305456,freq=1.0), product of:\n            0.047903106 = queryWeight, product of:\n              0.85714287 = boost\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.0077520725 = queryNorm\n            3.604646 = fieldWeight in 305456, product of:\n              1.0 = tf(freq=1.0), with freq of:\n                1.0 = termFreq=1.0\n              7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                635.0 = docFreq\n                316313.0 = docCount\n              0.5 = fieldNorm(doc=305456)\n      0.12161691 = sum of:\n        0.12161691 = weight(title_de:magic in 305456) [ClassicSimilarity], result of:\n          0.12161691 = score(doc=305456,freq=1.0), product of:\n            0.038838807 = queryWeight, product of:\n              0.8 = boost\n              6.262649 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                1638.0 = docFreq\n                316313.0 = docCount\n              0.0077520725 = queryNorm\n            3.1313245 = fieldWeight in 305456, product of:\n              1.0 = tf(freq=1.0), with freq of:\n                1.0 = termFreq=1.0\n              6.262649 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                1638.0 = docFreq\n                316313.0 = docCount\n              0.5 = fieldNorm(doc=305456)\n    0.5 = coord(2/4)\n"
      },
      "QParser":"ExtendedDismaxQParser"
}

Этот запрос работает даже с большим параметром «мм» (например, 90%):

"q":"(somsung~2 majic~2) OR (somsung^3 majic^3)"

Но проблема в том, что я получаю 430 результатов (вместо 6 желаемых). Вот отладка с примером неправильного продукта:

"debug":{
      "rawquerystring":"(somsung~2 majic~2) OR (somsung^3 majic^3)",
      "querystring":"(somsung~2 majic~2) OR (somsung^3 majic^3)",
      "parsedquery":"(+((DisjunctionMaxQuery((title_de:somsung~2)) DisjunctionMaxQuery((title_de:majic~2))) (DisjunctionMaxQuery((title_de:somsung))^3.0 DisjunctionMaxQuery((title_de:majic))^3.0))~1 DisjunctionMaxQuery((title_de:\"somsung 2 majic 2 somsung 3 majic 3\")))/no_coord",
      "parsedquery_toString":"+((((title_de:somsung~2) (title_de:majic~2)) (((title_de:somsung))^3.0 ((title_de:majic))^3.0))~1) (title_de:\"somsung 2 majic 2 somsung 3 majic 3\")",
      "explain":{
            "113746":"\n0.1275867 = sum of:\n  0.1275867 = product of:\n    0.2551734 = sum of:\n      0.2551734 = product of:\n        0.5103468 = sum of:\n          0.5103468 = sum of:\n            0.26860356 = weight(title_de:losung in 296822) [ClassicSimilarity], result of:\n              0.26860356 = score(doc=296822,freq=1.0), product of:\n                0.037257966 = queryWeight, product of:\n                  0.6666666 = boost\n                  7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                    635.0 = docFreq\n                    316313.0 = docCount\n                  0.0077520725 = queryNorm\n                7.209292 = fieldWeight in 296822, product of:\n                  1.0 = tf(freq=1.0), with freq of:\n                    1.0 = termFreq=1.0\n                  7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                    635.0 = docFreq\n                    316313.0 = docCount\n                  1.0 = fieldNorm(doc=296822)\n            0.24174322 = weight(title_de:osung in 296822) [ClassicSimilarity], result of:\n              0.24174322 = score(doc=296822,freq=1.0), product of:\n                0.033532172 = queryWeight, product of:\n                  0.6 = boost\n                  7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                    635.0 = docFreq\n                    316313.0 = docCount\n                  0.0077520725 = queryNorm\n                7.209292 = fieldWeight in 296822, product of:\n                  1.0 = tf(freq=1.0), with freq of:\n                    1.0 = termFreq=1.0\n                  7.209292 = idf, computed as log((docCount+1)/(docFreq+1)) + 1 from:\n                    635.0 = docFreq\n                    316313.0 = docCount\n                  1.0 = fieldNorm(doc=296822)\n        0.5 = coord(1/2)\n    0.5 = coord(1/2)\n"
      },
      "QParser":"ExtendedDismaxQParser"
}

Итак, хотя я получил лучшие результаты, мне все еще нужно улучшить поиск, и я до сих пор не знаю, какой способ выбрать и почему я получаю такие результаты.


person Aronsky    schedule 29.07.2017    source источник


Ответы (2)


Я думаю, что edismax НЕ поддерживает нечеткий оператор ~. здесь есть давно исправленное исправление, которое разработчик использовал в производстве для давно, но он еще не попал в кодовую базу Solr.

person Persimmonium    schedule 30.07.2017
comment
Хорошо, если fuzzy не поддерживается для edismax, почему в моем запросе 'q=aple~2 iphane~2' находит правильные результаты? Интерпретируется как стандартный запрос? - person Aronsky; 30.07.2017
comment
используйте degugQuery=true и давайте выясним - person Persimmonium; 30.07.2017
comment
Я обновил описание новыми экспериментами и результатами отладки. Похоже, edismax действительно умеет работать с нечеткими запросами из коробки. Теперь я запутался еще больше, чем раньше :) - person Aronsky; 30.07.2017

edismax работает с fuzzy, однако, когда вы включаете mm=90, вы фактически говорите, что solr должен соответствовать 90 точным фразам. Это кайф!

Удаление этого или использование низкого процента, например 50%, позволит работать некоторой нечеткости.

person F.O.O    schedule 08.09.2018