Буст стоп-слова исключает результаты из поиска


#1

Здравствуйте.
Проблема такая: для улучшения качества поиска у нас перед запросом в Эластик текст запроса проходит предварительную обработку. В ходе этой обработки на одном из этапов для слов, которые стоят перед "в", "на" и "для" добавляется буст. Например, для запроса "картина в кино" запрос получится "картина^3 в кино".
Буквально вчера обнаружили, что если мы забустили стоп-слово, то Эластик ничего не возвращает. Пример запроса:

"query": {
    "bool": {
      "minimum_should_match": "0",
      "must": {
        "multi_match": {
          "fields": [
            "items.first_word.ru_ru^6",
            "items.name.ru_ru^3",
            "items.materials.ru_ru",
            "items.authors.ru_ru",
            "items.attrs.ru_ru",
            "items.series_name.ru_ru",
            "items.tags.ru_ru",
            "items.trademark_tags.ru_ru",
            "items.trademark_name.ru_ru^2",
            "items.country_name.ru_ru",
            "items.category_name.ru_ru",
            "items.category_tags.ru_ru"
          ],
          "operator": "and",
          "query": "вино как^3 в кино",
          "tie_breaker": 0,
          "type": "cross_fields"
        }
      },
      "should": [
        {
          "term": {
            "items.is_adult": false
          }
        },
        {
          "term": {
            "items.is_our_trademark": true
          }
        },
        {
          "term": {
            "items.is_remote_store": false
          }
        }
      ]
    }
  }

При этом слово "как" помечено стоп-словом для индекса. И этот запрос ничего не возвращает. Если буст со слова "как" убрать, то будет корректно возвращен один найденный результат.
Что хуже, на проде, где Эластик версии 6.3 этот запрос ничего не возвращает, но на одном из тестовых Эластиков, где версия 6.4 этот же запрос работает нормально. Настройки стоп-слов в индексах одинаковые, я проверил.
Я локально сэмулировал эту же ситуацию и прогнал запрос через все последние официальные docker-образы от версии 6.3 до версии 6.6 - везде запрос с бустом стоп-слова ничего не возвращает.
Мы, конечно, будет проверять слово перед бустом на то, является ли оно стоп-словом, но все же интересно - это фича такая или баг? Или у нас где-то настройки неправильные?


#2

Я, оказывается, неправильно локально тестировал. В 6.3 буст стоп-слова исключает результат поиска, а в 6.4 уже все нормально. Значит, где-то все-таки поправили. Будем обновлять прод, когда получится.


(Mayya Sharipova) #3

match и multi_match queries не поддерживают query parsing. Вы не можете использовать такие операторы как ^, * в match запросах. Эти операторы можно использовать только в запросах query_string.

A вообщем есть API который вам поможет посмотреть как выглядит ваш запрос: _validate/query?explain=true

Например, учитывая что "как" - это stop word:

GET index1/_validate/query?explain=true
{
  "query": {
    "match": {
      "category": {
        "query": "вино как^3 в кино",
        "operator": "and"
      }
    }
  }
}

выдаст результат который вы не ожидаете где один из терминов для поиска "3":

 "explanations": [
    {
      "index": "index1",
      "valid": true,
      "explanation": "+category:вино +category:3 +category:в +category:кино"
    }
  ]

Тогда как на запросы query_string будет ожидаемый результат:

{
  "query": {
    "query_string": {
      "query": "вино как^3 в кино",
      "default_field": "category",
      "default_operator": "and"
    }
  }
}
"explanations": [
    {
      "index": "index1",
      "valid": true,
      "explanation": "+category:вино +category:в +category:кино"
    }
  ]

#4

Спасибо за обратную связь. Каюсь, я ввел в заблуждение неправильным запросом - не то скопировал. Для буста у нас, конечно, используется query_string, а multi_match используется, когда буста нет. Правильный вариант запроса с бустом:

"query": {
    "bool": {
      "minimum_should_match": "0",
      "must": {
        "query_string": {
          "default_operator": "and",
          "fields": [
            "items.first_word.ru_ru^6",
            "items.name.ru_ru^3",
            "items.materials.ru_ru",
            "items.authors.ru_ru",
            "items.attrs.ru_ru",
            "items.series_name.ru_ru",
            "items.tags.ru_ru",
            "items.trademark_tags.ru_ru",
            "items.trademark_name.ru_ru^2",
            "items.country_name.ru_ru",
            "items.category_name.ru_ru",
            "items.category_tags.ru_ru"
          ],
          "query": "вино как^3 в кино",
          "type": "cross_fields"
        }
      },
      "should": [
        {
          "term": {
            "items.is_adult": false
          }
        },
        {
          "term": {
            "items.is_our_trademark": true
          }
        },
        {
          "term": {
            "items.is_remote_store": false
          }
        }
      ]
    }
  }

Проблема в версии 6.3 с таким запросом все равно есть. Вот эксплейн для версии 6.4:

{
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "valid": true,
  "explanations": [
    {
      "index": "catalog",
      "valid": true,
      "explanation": "ToParentBlockJoinQuery (+(+(+blended(terms:[items.category_name.ru_ru:вино, items.trademark_tags.ru_ru:вино, items.country_name.ru_ru:вино, items.series_name.ru_ru:вино, items.authors.ru_ru:вино, items.name.ru_ru:вино^3.0, items.category_tags.ru_ru:вино, items.trademark_name.ru_ru:вино^2.0, items.materials.ru_ru:вино, items.attrs.ru_ru:вино, items.tags.ru_ru:вино, items.first_word.ru_ru:вино^6.0]) +blended(terms:[items.category_name.ru_ru:кино, items.trademark_tags.ru_ru:кино, items.country_name.ru_ru:кино, items.series_name.ru_ru:кино, items.authors.ru_ru:кино, items.name.ru_ru:кино^3.0, items.category_tags.ru_ru:кино, items.trademark_name.ru_ru:кино^2.0, items.materials.ru_ru:кино, items.attrs.ru_ru:кино, items.tags.ru_ru:кино, items.first_word.ru_ru:кино^6.0])) items.is_adult:F items.is_our_trademark:T items.is_remote_store:F) #_type:__items)"
    }
  ]
}

Вот эксплейн для версии 6.3:

{
    "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "valid": true,
  "explanations": [
    {
      "index": "catalog",
      "valid": true,
      "explanation": "ToParentBlockJoinQuery (+(+blended(terms:[items.category_name.ru_ru:вино, items.trademark_tags.ru_ru:вино, items.country_name.ru_ru:вино, items.series_name.ru_ru:вино, items.authors.ru_ru:вино, items.name.ru_ru:вино^3.0, items.category_tags.ru_ru:вино, items.trademark_name.ru_ru:вино^2.0, items.materials.ru_ru:вино, items.attrs.ru_ru:вино, items.tags.ru_ru:вино, items.first_word.ru_ru:вино^6.0]) +(MatchNoDocsQuery(\"[multi_match] list of group queries was empty\"))^3.0 +blended(terms:[items.category_name.ru_ru:кин, items.trademark_tags.ru_ru:кин, items.country_name.ru_ru:кин, items.series_name.ru_ru:кин, items.authors.ru_ru:кин, items.name.ru_ru:кин^3.0, items.category_tags.ru_ru:кин, items.trademark_name.ru_ru:кин^2.0, items.materials.ru_ru:кин, items.attrs.ru_ru:кин, items.tags.ru_ru:кин, items.first_word.ru_ru:кин^6.0])) items.is_adult:F items.is_our_trademark:T items.is_remote_store:F)"
    }
  ]
}

Для версии 6.3 в эксплейне есть строка +(MatchNoDocsQuery("[multi_match] list of group queries was empty"))^3.0(собственно стоп-слово, видимо), а в 6.4 ее уже нет.


(Mayya Sharipova) #5

Да вы правы - действительно до версии в 6.4.1, мы создавали MatchNoDocsQuery если термин был не найден (в случае с stop word). Так как у вас queries объединятся AND, то один MatchNoDocsQuery приводит к тому что вообще никаких результатов не выводиться.

И как вы правильно заметили этот проблема была решена с версии 6.4.1. Вот это PR на нее. Решение - использовать версии начинаю с 6.4.1