@chuckskull Правильно, я упустил этот момент в первоначальном ответе. Пожалуйста, проверьте снова!

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

SELECT COUNT(*) FROM
(
   SELECT
    senderResellerId,
    SUM(requestAmountValue) AS t_amount
   FROM
    transactions
   GROUP BY
    senderResellerId
   HAVING
    t_amount > 10000 ) AS dum;

До сих пор я мог группировать по senderResellerId по совокупности терминов. Но когда я применяю фильтры, это не работает, как ожидалось.

Эластичный запрос

{
  "aggregations": {
    "reseller_sale_sum": {
      "aggs": {
        "sales": {
          "aggregations": {
            "reseller_sale": {
              "sum": {
                "field": "requestAmountValue"
              }
            }
          }, 
          "filter": {
            "range": {
              "reseller_sale": { 
                "gte": 10000
              }
            }
          }
        }
      }, 
      "terms": {
        "field": "senderResellerId", 
        "order": {
          "sales>reseller_sale": "desc"
        }, 
        "size": 5
      }
    }
  }, 
  "ext": {}, 
  "query": {  "match_all": {} }, 
  "size": 0
}

Актуальный ответ

{
  "took" : 21,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "hits" : {
    "total" : 150824,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "reseller_sale_sum" : {
      "doc_count_error_upper_bound" : -1,
      "sum_other_doc_count" : 149609,
      "buckets" : [
        {
          "key" : "RES0000000004",
          "doc_count" : 8,
          "sales" : {
            "doc_count" : 0,
            "reseller_sale" : {
              "value" : 0.0
            }
          }
        },
        {
          "key" : "RES0000000005",
          "doc_count" : 39,
          "sales" : {
            "doc_count" : 0,
            "reseller_sale" : {
              "value" : 0.0
            }
          }
        },
        {
          "key" : "RES0000000006",
          "doc_count" : 57,
          "sales" : {
            "doc_count" : 0,
            "reseller_sale" : {
              "value" : 0.0
            }
          }
        },
        {
          "key" : "RES0000000007",
          "doc_count" : 134,
          "sales" : {
            "doc_count" : 0,
            "reseller_sale" : {
              "value" : 0.0
            }
          }
        }
          }
        }
      ]
    }
  }
}

Как видно из приведенного выше ответа, он возвращает реселлеров, ноreseller_sale агрегация равна нулю в результатах.

Более подробная информацияВот.

 Nikolay Vasiliev25 окт. 2017 г., 15:10
Можете ли вы предоставить используемое вами сопоставление ES и пару примеров документов?
 chuckskull25 окт. 2017 г., 15:37
@NikolayVasiliev Картирование обновляется здесь.discuss.elastic.co/t/sql-like-group-by-and-having/104705

Ответы на вопрос(1)

Решение Вопроса
РеализацияHAVINGподобное поведение

Вы можете использовать один изpipeline aggregationsа именноагрегация селектора ковша, Запрос будет выглядеть так:

POST my_index/tdrs/_search
{
   "aggregations": {
      "reseller_sale_sum": {
         "aggregations": {
            "sales": {
               "sum": {
                  "field": "requestAmountValue"
               }
            },
            "max_sales": {
               "bucket_selector": {
                  "buckets_path": {
                     "var1": "sales"
                  },
                  "script": "params.var1 > 10000"
               }
            }
         },
         "terms": {
            "field": "senderResellerId",
            "order": {
               "sales": "desc"
            },
            "size": 5
         }
      }
   },
   "size": 0
}

После помещения следующих документов в указатель:

  "hits": [
     {
        "_index": "my_index",
        "_type": "tdrs",
        "_id": "AV9Yh5F-dSw48Z0DWDys",
        "_score": 1,
        "_source": {
           "requestAmountValue": 7000,
           "senderResellerId": "ID_1"
        }
     },
     {
        "_index": "my_index",
        "_type": "tdrs",
        "_id": "AV9Yh684dSw48Z0DWDyt",
        "_score": 1,
        "_source": {
           "requestAmountValue": 5000,
           "senderResellerId": "ID_1"
        }
     },
     {
        "_index": "my_index",
        "_type": "tdrs",
        "_id": "AV9Yh8TBdSw48Z0DWDyu",
        "_score": 1,
        "_source": {
           "requestAmountValue": 1000,
           "senderResellerId": "ID_2"
        }
     }
  ]

Результат запроса:

"aggregations": {
      "reseller_sale_sum": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": "ID_1",
               "doc_count": 2,
               "sales": {
                  "value": 12000
               }
            }
         ]
      }
   }

То есть только теsenderResellerId чьи совокупные продажи>10000.

Подсчет ведер

Для реализации эквивалентаSELECT COUNT(*) FROM (... HAVING) можно использовать комбинациюагрегация сценария ведра с участиемагрегация по сумме, Хотя, кажется, нет прямого способа подсчитать, сколько ведерbucket_selector на самом деле выберите, мы можем определитьbucket_script что производит0 или же1 в зависимости от состояния иsum_bucket что производит егоsum:

POST my_index/tdrs/_search
{
   "aggregations": {
      "reseller_sale_sum": {
         "aggregations": {
            "sales": {
               "sum": {
                  "field": "requestAmountValue"
               }
            },
            "max_sales": {
               "bucket_script": {
                  "buckets_path": {
                     "var1": "sales"
                  },
                  "script": "if (params.var1 > 10000) { 1 } else { 0 }"
               }
            }
         },
         "terms": {
            "field": "senderResellerId",
            "order": {
               "sales": "desc"
            }
         }
      },
      "max_sales_stats": {
         "sum_bucket": {
            "buckets_path": "reseller_sale_sum>max_sales"
         }
      }
   },
   "size": 0
}

Выход будет:

   "aggregations": {
      "reseller_sale_sum": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            ...
         ]
      },
      "max_sales_stats": {
         "value": 1
      }
   }

Желаемое количество ведра находится вmax_sales_stats.value.

Важные соображения

Я должен указать на 2 вещи:

Функция является экспериментальной (начиная с ES 5.6 она все еще является экспериментальной, хотя она была добавлена ​​в2.0.0-beta1.)конвейерные агрегации применяются на основе результатов предыдущих агрегаций:

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

Это значит, чтоbucket_selector агрегация будет применяться после и в результатеterms агрегация наsenderResellerId, Например, если есть большеsenderResellerId чемsize изterms Агрегация определяет, вы не получитевсе идентификаторы в коллекции сsum(sales) > 10000, но только те, которые появляются на выходеterms агрегация. Рассмотрите возможность использования сортировки и / или установите достаточноsize параметр.

Это также относится ко второму случаю,COUNT() (... HAVING), который будет считать только те сегменты, которые фактически присутствуют в выходных данных агрегации.

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

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

 chuckskull27 окт. 2017 г., 19:27
Я просто хочу количество ведер, а не содержимое ведер.
 Nikolay Vasiliev29 окт. 2017 г., 11:50
@chuckskull Правильно, я упустил этот момент в первоначальном ответе. Пожалуйста, проверьте снова!
 chuckskull27 окт. 2017 г., 19:08
Большое спасибо. :) Можете ли вы сказать мне, как рассчитать количество сегментов, если я упомяну INT_MAX в качестве моего размера?

Ваш ответ на вопрос