В Elasticsearch, как я могу выполнить вложенные субагрегации? - PullRequest
1 голос
/ 02 июня 2019

В Кибане я создаю свой индекс следующим образом:

PUT cars
{  
   "mappings":{  
      "_doc":{  
         "properties":{  
            "metadata":{  
               "type":"nested",
               "properties":{  
                  "str_value":{  
                     "type":"keyword"
                  }
               }
            }
         }
      }
   }
}

Затем вставляю три записи:

POST /cars/_doc/1
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Ford"
    },
    {
      "key": "price",
      "int_value": 1000
    }
  ]
}
PUT /cars/_doc/2
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Ford"
    },
    {
      "key": "price",
      "int_value": 2000
    }
  ]
}
PUT /cars/_doc/3
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Holden"
    },
    {
      "key": "price",
      "int_value": 2500
    }
  ]
}

Схема немного нетрадиционная, но я разработалИндексируйте этот способ, чтобы избежать взрыва картографирования:

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html

Что я хотел бы сделать, это получить все мои модели автомобилей и сумму цен на эти модели, т.е.Форд 3000 долларов, а Холден 2500 долларов.На данный момент у меня есть:

GET /cars/_search
{  
   "aggs":{  
      "metadata":{  
         "nested":{  
            "path":"metadata"
         },
         "aggs":{  
            "model_filter":{  
               "filter":{  
                  "term":{  
                     "metadata.key":"model"
                  }
               },
               "aggs":{  
                  "model_counter":{  
                     "terms":{  
                        "field":"metadata.str_value",
                        "size":1000
                     }
                  }
               }
            }
         }
      }
   }
}

Это помогает мне пройти часть пути, потому что возвращает модели автомобилей и количество документов:

  "aggregations": {
    "metadata": {
      "doc_count": 6,
      "model_filter": {
        "doc_count": 3,
        "model_counter": {
          "doc_count_error_upper_bound": 0,
          "sum_other_doc_count": 0,
          "buckets": [
            {
              "key": "Ford",
              "doc_count": 2
            },
            {
              "key": "Holden",
              "doc_count": 1
            }
          ]
        }
      }
    }
  }

Как я могу изменить свой запрос, чтобы добавитьсубагрегация, которая покажет сумму цен, т.е. 3000 для Ford (сумма двух документов) и 2500 для Holden (сумма одного документа)

1 Ответ

0 голосов
/ 02 июня 2019

Ниже запрос должен помочь вам для того, что вы ищете.

Я просто добавил к вашему решению для этого.Я использовал Обратное вложенное агрегирование и затем применил Суммарное агрегирование пост снова, используя Вложенное агрегирование .

Итак, ваша иерархия запросов выглядит следующим образом:

Nested Aggregation
- Terms Aggregation
 - Reverse Nested Aggregation to back to parent doc
  - Nested Aggregation to enter into nested price document
   - Sum Aggregation to calculate all the prices

Запрос агрегации:

POST <your_index_name>/_search
{  
   "size":0,
   "aggs":{  
      "metadata":{  
         "nested":{  
            "path":"metadata"
         },
         "aggs":{  
            "model_filter":{  
               "filter":{  
                  "term":{  
                     "metadata.key":"model"
                  }
               },
               "aggs":{  
                  "model_counter":{  
                     "terms":{  
                        "field":"metadata.str_value",
                        "size":1000
                     },
                     "aggs":{  
                        "reverseNestedAgg":{  
                           "reverse_nested":{},
                           "aggs":{  
                              "metadata":{  
                                 "nested":{  
                                    "path":"metadata"
                                 },
                                 "aggs":{  
                                    "sum":{  
                                       "sum":{  
                                          "field":"metadata.int_value"
                                       }
                                    }
                                 }
                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
}

Обратите внимание, что я добавил "size": 0, чтобы возвращать только агрегациюзапрос.Вы можете изменить его в соответствии с вашими требованиями.

Решение по агрегации:

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "metadata" : {
      "doc_count" : 6,
      "model_filter" : {
        "doc_count" : 3,
        "model_counter" : {
          "doc_count_error_upper_bound" : 0,
          "sum_other_doc_count" : 0,
          "buckets" : [
            {
              "key" : "Ford",
              "doc_count" : 2,
              "reverseNestedAgg" : {
                "doc_count" : 2,
                "metadata" : {
                  "doc_count" : 4,
                  "sum" : {
                    "value" : 3000.0
                  }
                }
              }
            },
            {
              "key" : "Holden",
              "doc_count" : 1,
              "reverseNestedAgg" : {
                "doc_count" : 1,
                "metadata" : {
                  "doc_count" : 2,
                  "sum" : {
                    "value" : 2500.0
                  }
                }
              }
            }
          ]
        }
      }
    }
  }
}

Обратите внимание, что я проверил вышеупомянутый запрос в ES версии 7.

Важное примечание:

Если ваш документзаканчивается в следующем формате, тогда вышеупомянутый запрос не будет работать.

POST /cars/_doc/1
{
  "metadata": [
    {
      "key": "model",
      "str_value": "Ford"
    },
    {
      "key": "price",
      "int_value": 1000
    },
    {
      "key": "something else",
      "int_value": 1000
    }
  ]
}
// There are three nested documents with two documents having int_value field

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...