Фильтрация по нескольким полям из вложенного объекта с помощью Elasticsearch

Я новичок в Elasticsearch и пытаюсь написать несколько запросов, которые не работают. У меня есть информация о людях, и я хочу запросить людей на основе некоторых атрибутов.

Вот часть сопоставления в Elasticsearch:

"properties": {
    "doc": {
        ...
        "languages": [{
                "language": {
                    "type": "text",
                    "null_value": "NULL"
                },
                "level": {
                    "type": "integer",
                    "null_value": "NULL"
                }
            }],
         ...
    }
}

Например, я хочу отфильтровать всех людей, которые говорят на английском на уровне выше 3 и на японском на уровне выше . 2.

Я уже пробовал этот подход, который не дает ожидаемого результата.

"size": 1000,
"from": 0,
"query": {
  "bool": {
    "should": [
      {
        "bool": {
          "must": [
            {"match": {"languages.language": "english"}},
            {"range": {"languages.search_value": {"gt": 3}}}
          ]
        }
      },
      {
        "bool": {
          "must": [
            {"match": {"languages.language": "japanese"}},
            {"range": {"languages.search_value": {"gt": 2}}}
          ]
        }
      }
    ]
  }
}

Приведенный выше запрос возвращает всех людей, говорящих на английском и японском языках, но уровни этих языков не совпадают. Есть люди, которые говорят по-английски с 4-м уровнем (что нормально), но по-японски с 1-м уровнем (что не является нормальным) и по-немецки с 5-м уровнем. Я думаю, проблема в том, что вместо того, чтобы искать желаемый уровень только для указанных языков , мой запрос ищет уровни на всех языках, на которых говорят люди.

Итак, результат, который я ожидаю от запроса, состоит в том, чтобы получить всех людей, которые говорят по-английски с уровнем 4 или 5 и по-японски с уровнем 3, 4 или 5 (оба в одно и то же время) . Меня не волнуют другие языки, на которых они говорят, и их уровни.

Любая помощь или идея, как я могу решить эту проблему, приветствуется.


person Antonio    schedule 02.09.2019    source источник


Ответы (1)


Вам необходимо использовать вложенное сопоставление для языков и уровней .

Отображение

PUT /employee
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "languages": {
        "type": "nested",
        "properties": {
          "language": {
            "type": "text"
          },
          "level": {
            "type": "integer"
          }
        }
      }
    }
  }
}

Данные:

 [
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "vkVy9WwBecJvLwMRPgIH",
        "_score" : 1.0,
        "_source" : {
          "name" : "User1",
          "languages" : [
            {
              "language" : "English",
              "level" : 3
            },
            {
              "language" : "Japanese",
              "level" : 2
            }
          ]
        }
      },
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "v0Vy9WwBecJvLwMRagL6",
        "_score" : 1.0,
        "_source" : {
          "name" : "User2",
          "languages" : [
            {
              "language" : "English",
              "level" : 3
            },
            {
              "language" : "Japanese",
              "level" : 1
            }
          ]
        }
      },
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "wEVy9WwBecJvLwMRlQIs",
        "_score" : 1.0,
        "_source" : {
          "name" : "User3",
          "languages" : [
            {
              "language" : "English",
              "level" : 3
            },
            {
              "language" : "Spanish",
              "level" : 1
            }
          ]
        }
      },
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "wUWD9WwBecJvLwMRWgIq",
        "_score" : 1.0,
        "_source" : {
          "name" : "User4",
          "languages" : [
            {
              "language" : "English",
              "level" : 2
            },
            {
              "language" : "French",
              "level" : 1
            }
          ]
        }
      }
    ]

Запрос

GET employee/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "languages",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "languages.language": "English"
                    }
                  },
                  {
                    "range": {
                      "languages.level": {
                        "gte": 3
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        {
          "nested": {
            "path": "languages",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "languages.language": "Japanese"
                    }
                  },
                  {
                    "range": {
                      "languages.level": {
                        "gte": 2
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Результат:

 [
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "vkVy9WwBecJvLwMRPgIH",
        "_score" : 3.974081,
        "_source" : {
          "name" : "User1",
          "languages" : [
            {
              "language" : "English",
              "level" : 3
            },
            {
              "language" : "Japanese",
              "level" : 2
            }
          ]
        }
      }
    ]

Решение довольно тривиальное, вам нужно понять вложенный тип. Ссылка в этом ответе имеет объяснение этому

person jaspreet chahal    schedule 03.09.2019
comment
Итак, я внес необходимые изменения в сопоставление, но когда я выполняю запрос, я получаю следующее исключение: тип: незаконное_состояние_исключение, причина: [вложенный] вложенный объект по пути [языки] не имеет вложенного типа - person Antonio; 04.09.2019
comment
В соответствии с сопоставлением исключений не обновляется. Можете ли вы вставить свое сопоставление и запрос - person jaspreet chahal; 04.09.2019
comment
"languages": { "type": "nested", "properties": { "language": { "type": "text", "null_value": "NULL" }, "level": { "type": "integer", "null_value": "NULL" } } Запрос такой же, как у вас - person Antonio; 04.09.2019
comment
null_value: NULL не допускается для текстового и целочисленного типов (должно быть ошибка). Я попытался изменить тип на ключевое слово везде, где указано значение null_value: NULL, и попробовал запрос, он возвращает данные. Попробуйте GET ‹index_name›/_mapping, он должен дать сопоставление и проверить, обновляется ли сопоставление. - person jaspreet chahal; 04.09.2019
comment
Да, у меня была проблема с отображением (ошибки, которые не были показаны), но, наконец, я их решил. Спасибо за помощь! - person Antonio; 05.09.2019