Поиск во вложенном поле нескольких значений в одном поле с помощью elasticsearch

#elasticsearch

#elasticsearch

Вопрос:

Я пытаюсь запросить вложенные свойства с несколькими значениями.

Вот пример, который будет понятнее.

Создайте индекс с вложенным полем

     curl -X DELETE "http://localhost:9200/testing_nested_query/"
    curl -X POST "http://localhost:9200/testing_nested_query/" -d '{
        "mappings": {
            "class": {
              properties: {
                title: {"type": "string"},
                "students": {
                  "type": "nested",
                  "properties": {
                    "name": {"type": "string"}
                  }
                }
              }
            }
        }

    }'
  

Добавьте несколько значений

     curl -XPUT 'http://localhost:9200/testing_nested_query/class/1' -d '{
      "title": "class1",
      "students": [{"name": "john"},{"name": "jack"},{"name": "jim"}]
    }'

    curl -XPUT 'http://localhost:9200/testing_nested_query/class/2' -d '{
      "title": "class2",
      "students": [{"name": "john"},{"name": "chris"},{"name": "alex"}]
    }'
  

Запрос для всех классов, где находится Джон (2 попадания, как и ожидалось)

 curl -XGET 'http://localhost:9200/testing_nested_query/class/_search' -d '{
  "query": {
    "nested": {
      "path":"students",
      "query": {
        "bool": {
          "must": [
            {"match": {"students.name": "john"}}
          ]
        }
      }
    }
  }
}'
  

Запрос классов, в которых учатся Джон и Джек (0 результатов вместо 1)

 curl -XGET 'http://localhost:9200/testing_nested_query/class/_search' -d '{
  "query": {
    "nested": {
      "path":"students",
      "query": {
        "bool": {
          "must": [
            {"match": {"students.name": "john"}},
            {"match": {"students.name": "jack"}}
          ]
        }
      }
    }
  }
}'
  

Я пробовал использовать match и filter, но я никогда не могу заставить запрос возвращать ожидаемые значения.

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

1. Запрос будет работать, просто используя «должен» вместо «must».

2. Нет, с помощью «should» он возвращает 2 попадания вместо одного.

3. Вы правы, я неправильно истолковал вопрос.

Ответ №1:

Это просто нужно немного изменить:

 {
  "query": {
    "bool": {
        "must": [
           {
               "nested": {
                  "path":"students",
                  "query": {
                    "bool": {
                      "must": [
                        {"match": {"name": "john"}}
                      ]
                    }
                  }
                }
           },
           {
               "nested": {
                  "path":"students",
                  "query": {
                    "bool": {
                      "must": [
                        {"match": {"name": "jack"}}
                      ]
                    }
                  }
                }
           }
        ]
    }
  }
}
  

Почему?

По сути, во вложенном запросе запрос и фильтр совместно выполняются для одного вложенного документа — в вашем случае для одного имени. Таким образом, ваш запрос поднимет каждый вложенный документ и попытается найти каждый документ, который имеет name значение john и jack одновременно, что невозможно.

Мой запрос пытается найти индексированный документ, в котором один вложенный документ name равен john , а другой вложенный документ name равен jack . Таким образом, в основном один вложенный запрос пытается полностью сопоставить один вложенный документ.

Чтобы доказать, что я предлагаю, попробуйте это:

Создайте тот же индекс с тем же отображением, что и вы

** Затем проиндексируйте следующие документы **

 curl -XPUT 'http://localhost:9200/testing_nested_query/class/1' -d '{
      "title": "class1",
      "students": [{"name": "john", "age": 4},{"name": "jack", "age": 1},{"name": "jim", "age": 9}]
    }'

curl -XPUT 'http://localhost:9200/testing_nested_query/class/2' -d '{
      "title": "class1",
      "students": [{"name": "john", "age": 5},{"name": "jack", "age": 4},{"name": "jim", "age": 9}]
    }'
  

Теперь выполните следующие запросы:

 {
  "query": {
       "nested": {
          "path":"students",
          "query": {
            "bool": {
              "must": [
                {"match": {"name": "john"}},
                {"match": {"age": 4}}
              ]
            }
          }
        }
  }
}
  

Согласно вашим ожиданиям, это должно соответствовать двум документам, но на самом деле соответствует только одному. Потому что существует только один вложенный документ, в котором оба значения name равны john age и 4 равны в,,.

Надеюсь, это поможет.

Ответ №2:

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

 {
  "query": {
    "bool": {
      "must": [{
        "nested": {
          "path": "students",
          "query": {
            {
              "term": {
                "name": "john"
              }
            }
          }
        }
      }, {
        "nested": {
          "path": "students",
          "query": {
            {
              "term": {
                "name": "jack"
              }
            }
          }
        }
      }]
    }
  }
}