Подтвердить что ты не робот

Точный поиск по типу объекта массива с использованием elasticsearch

Я ищу способ сделать точный массив матчей в упругом поиске. Скажем, это мои документы:

{"id": 1, "categories" : ["c", "d"]}
{"id": 2, "categories" : ["b", "c", "d"]}
{"id": 3, "categories" : ["c", "d", "e"]}
{"id": 4, "categories" : ["d"]}
{"id": 5, "categories" : ["c", "d"]}

Есть ли способ поиска всего документа с точно категориями "c" и "d" (документы 1 и 5), не более или менее?

В качестве бонуса: поиск "одной из этих" категорий также должен быть возможен (например, вы могли бы искать "c" и получать 1, 2, 3 и 5)

Любой умный способ решить эту проблему?

4b9b3361

Ответ 1

Если у вас есть дискретный, известный набор категорий, вы можете использовать запрос bool:

"bool" : {
    "must" : {
        "terms" : { "categories" : ["c", "d"],
             minimum_should_match : 2
         }
    },
    "must_not" : {
        "terms" : { "categories" : ["a", "b", "e"],
             minimum_should_match : 1
         }
    }
}

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

{"id": 1, "categories" : ["c", "d"], "categorieskey" : "cd"}

Что-то вроде этого. Затем вы можете легко запросить запрос терминов точно для результатов, которые вы хотите, например:

term { "categorieskey" : "cd" }

И вы все равно можете искать не исключительно, как:

term { "categories" : "c" }

Запросить для двух категорий, которые должны присутствовать, достаточно просто, но тогда предотвращение присутствия любых других потенциальных категорий немного сложнее. Вы могли бы это сделать, наверное. Вероятно, вы захотите написать запрос, чтобы найти записи с обоими, а затем применить к нему фильтр, исключая любые записи с категориями, отличными от указанных. Насколько я знаю, Lucene, по сути, предназначен для обработки.

Честно говоря, у меня проблемы с хорошим фильтром для использования здесь. Вам может понадобиться фильтр script, или вы можете фильтровать результаты после их получения.

Ответ 2

Я нашел решение для нашего случая использования, которое, похоже, работает. Он опирается на два фильтра и знание того, сколько категорий мы хотим сопоставить. Мы используем фильтр терминов и фильтр script, чтобы проверить размер массива. В этом примере marketBasketList похож на ваш список категорий.

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "siteId": 4
          }
        },
        {
          "match": {
            "marketBasketList": {
              "query": [
                10,
                11
              ],
              "operator": "and"
            }
          }
        }
      ]
    },
    "boost": 1,
    "filter": {
      "and": {
        "filters": [
          {
            "script": {
              "script": "doc['marketBasketList'].values.length == 2"
            }
          },
          {
            "terms": {
              "marketBasketList": [
                10,
                11
              ],
              "execution": "and"
            }
          }
        ]
      }
    }
  }
}