Эластичный поиск: запрос точного соответствия в массиве строк

#elasticsearch

#elasticsearch

Вопрос:

Учитывая этот документ:

 {"name": "Perfect Sunny-Side Up Eggs","ingredientList": ["canola oil","eggs"]}
  

Как я могу создать запрос в эластичном поиске, чтобы возвращать точные совпадения в строковом массиве с заданным термином запроса «масляные яйца», пока это то, что у меня есть, но он возвращает другие нерелевантные документы:

 POST /recipes/recipe/_search
{
   "query": {
      "match": {
         "ingredientList": {
            "query": [
               "oil",
               "eggs"
            ],
            "operator": "and"
         }
      }
   }
}
  

например, этот документ возвращается, но он не содержит «масло». Результаты должны содержать только «масло» и «яйца»:

 {"name": "Quick Baked French Toast","ingredientList": ["butter","cinnamon raisin bread","eggs"]}
  

Комментарии:

1. Вам нужен bool запрос с несколькими Must предложениями: elastic.co/guide/en/elasticsearch/reference/current /…

Ответ №1:

Ваш запрос будет выглядеть следующим образом:

 {
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "ingredientList": "oil"
          }
        },
        {
          "term": {
            "ingredientList": "eggs"
          }
        }
      ]
    }
  }
}
  

Дает мне результаты:

 {
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "ingredients",
      "_type" : "recipe",
      "_id" : "AVeprXFrNutW6yNguPqp",
      "_score" : 1.0,
      "_source" : {
        "name" : "Perfect Sunny-Side Up Eggs",
        "ingredientList" : [ "canola oil", "eggs" ]
      }
    } ]
  }
}
  

Комментарии:

1. Большое вам спасибо!

2. Здравствуйте, я знаю, что это было опубликовано давно, но я пытаюсь сделать что-то подобное, за исключением того, что в моем случае оно должно содержать точную фразу «масло», а не «масло канолы». Вы знаете, как это сделать? Спасибо.

3. @tomfl Привет, я ищу то же самое, вы решили это?

4. @Vladimir Хм, если я правильно помню, мне пришлось изменить анализатор на keyword : elastic.co/guide/en/elasticsearch/reference/current /…

5. чтобы "oil" не совпадать "canola oil" , затем скажите "term": { "ingredientList.keyword": "oil" }

Ответ №2:

У Elastic нет API для точного сопоставления массива. Но то же самое может быть достигнуто с помощью двух методов:

  1. Использование нескольких обязательных блоков (не предпочтительно)

  2. Используя terms set запрос и script

      "query": {
       "bool": {
         "must": [
           {
             "terms_set": {
               "ingredientList": {
                 "terms": ingredients,
                 "minimum_should_match_script": {
                   "source": "Math.min(params.num_terms, {})".format(len(ingredients))
                 }
               }
             }
           },
           {
             "script": {
               "script": {
                 "inline": "doc['ingredientList'].length == params.list_length",
                 "lang": "painless",
                 "params": {
                   "list_length": len(ingredients)
                 }
               }
             }
           }
         ]
       }
     }