Запрос Elasticsearch по общим свойствам: ключевые слова и числовые значения

#elasticsearch

#elasticsearch

Вопрос:

У меня есть это сопоставление в ES 7.9:

 {
  "mappings": {
    "properties": {
      "cid": {
        "type": "keyword",
        "store": true
      },
      "id": {
        "type": "keyword",
        "store": true
      },
      "a": {
        "type": "nested",
        "properties": {
          "attribute":{
            "type": "keyword"      
          },  
          "key": {
            "type": "keyword"
          },
          "num": {
            "type": "float"
          }
        }
      }
    }
  }
}

 

И некоторые документы, проиндексированные как:

 
{
    "cid": "177",
    "id": "1",
    "a": [
        {
            "attribute": "tags",
            "key": [
                "heel",
                "thong",
                "low_heel",
                "economic"
            ]
        },
        {
            "attribute": "weight",
            "num": 15
        }
    ]
}
 

В принципе, объект может иметь несколько атрибутов ( a массив свойств).

Эти атрибуты могут отличаться для каждого клиента. В этом примере у меня есть 2 типа атрибутов: tag и weight , однако другие документы могут иметь другие атрибуты, такие как vendor , size , power , и т.д., Поэтому модель должна быть достаточно общей, чтобы поддерживать заранее неизвестные атрибуты.

Атрибут может быть списком ключевых слов (например tags ) или числовым значением (например weight ).

Мне нужен запрос ES для извлечения документов ids с помощью этого псевдозапроса:

cid="177" and (tag="flat" or tag="heel") and tag="economic" and weight<20

Мне удалось выполнить этот запрос, который, похоже, работает должным образом:

 {
    "_source": ["id"],
    "query": {
        "bool": {
            "must" : [
                {"term" : { "cid" : "177" }},
                {
                    "nested": {
                        "path": "a",
                        "query": {
                            "bool":{
                                "must":[
                                    {"term" : { "a.attribute": "tags"}},
                                    {"terms" : { "a.key": ["flat","heel"]}}       
                                ]
                            }
                        }
                    }
                },
                {
                    "nested": {
                        "path": "a",
                        "query": {
                            "bool":{
                                "must":[
                                    {"term" : { "a.attribute": "tags"}},
                                    {"term" : { "a.key": "economic"}}       
                                ]
                            }
                        }
                    }
                },
                {
                    "nested": {
                        "path": "a",
                        "query": {
                            "bool":{
                                "must":[
                                    {"term" : { "a.attribute": "weight" } },
                                    {"range": { "a.num": {"lt": 20} } }
                                ]
                            }
                        }
                    }
                }                 
            ]            
        }
    }
}
 
  1. Правильный ли этот запрос или я случайно получаю правильные результаты?
  2. Является ли запрос (или сопоставление) оптимальным или я должен что-то переосмыслить?
  3. Можно ли упростить запрос?

Ответ №1:

  1. Запрос правильный.
  2. Сопоставление отличное, а запрос оптимальный.
  3. Хотя запрос можно упростить:
 {
  "_source": [
    "id"
  ],
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "cid": "177"
          }
        },
        {
          "nested": {
            "path": "a",
            "query": {
              "query_string": {
                "query": "a.attribute:tags AND ((a.key:flat OR a.key:heel) AND a.key:economic)"
              }
            }
          }
        },
        {
          "nested": {
            "path": "a",
            "query": {
              "query_string": {
                "query": "a.attribute:weight AND a.num:<20"
              }
            }
          }
        }
      ]
    }
  }
}
 

это было бы менее оптимально из-за того, что их query_strings все равно нужно было бы внутренне скомпилировать, по сути, в DSL запроса, который у вас есть выше. Кроме того, вам все равно понадобятся две отдельные nested группы so… Вы можете использовать то, что у вас есть.