我正试图向elasticsearch发出一个查询,该查询可以进行筛选、分组、总和聚合和排序。我有两个问题:查询应该是什么样子,弹性搜索的性能影响是什么?
让我举一个数据集的例子来支持我的问题。假设我有一套销售:
document type: 'sales' with the following fields and data:
sale_datetime | sold_product | sold_at_price
-----------------|---------------|--------------
2015-11-24 12:00 | some product | 100
2015-11-24 12:30 | some product | 100
2015-11-24 12:30 | other product | 100
2015-11-24 13:00 | other product | 100
2015-11-24 12:30 | some product | 200
2015-11-24 13:00 | some product | 200
我想发出一个查询:
- 仅考虑2015-11-24 12:15至2015-11-24 13:45期间的销售
- 按sold_product字段对结果进行分组
- 计算"每个产品的sold_at_price值总和"
- 按最大的"每产品sold_at_price值之和"排在第一位、第二位的顺序返回行,依此类推
将其应用于上面的样本数据集,将返回以下结果:
sold_product | sum of sold_at_price
--------------|--------------
some product | 300 // takes into account rows 2 and 5
other product | 100 // takes into account row 3
如果可以发出这样的查询,那么弹性搜索的重要性能含义是什么?如果需要考虑:
- 有许多(数十万,未来可能有数百万)独特的产品
- 产品名称可能包括多个(几十个)单词/术语(可以生成仅由一个单词组成的唯一产品名称,但这几乎会使数据量增加一倍)
- 通常有许多(数百万)条记录满足时间范围筛选器(在某些情况下,筛选器可以缩小到一个时间范围内的数万条记录,但不能保证)
提前感谢您的帮助!
这是聚合的典型用例。让我们首先创建一个索引并对数据的映射进行建模。对于sold_datetime
,我们有一个普通的date
字段,对于sold_at_price
,我们有另一个数字字段,并且对于sold_product
,我们有字符串类型的多字段。您会注意到,这个多字段有一个名为raw
的子字段,它是not_analyzed
,将用于在产品名称上创建聚合:
curl -XPUT localhost:9200/sales -d '{
"mappings": {
"sale": {
"properties": {
"sale_datetime": {
"type": "date"
},
"sold_product": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
},
"sold_at_price": {
"type": "double"
}
}
}
}
}'
现在,让我们使用新索引的_bulk
端点对样本数据集进行索引:
curl -XPOST localhost:9200/sales/sale/_bulk -d '
{"index": {}}
{"sold_datetime": "2015-11-24T12:00:00.000Z", "sold_product":"some product", "sold_at_price": 100}
{"index": {}}
{"sold_datetime": "2015-11-24T12:30:00.000Z", "sold_product":"some product", "sold_at_price": 100}
{"index": {}}
{"sold_datetime": "2015-11-24T12:30:00.000Z", "sold_product":"other product", "sold_at_price": 100}
{"index": {}}
{"sold_datetime": "2015-11-24T13:00:00.000Z", "sold_product":"other product", "sold_at_price": 100}
{"index": {}}
{"sold_datetime": "2015-11-24T12:30:00.000Z", "sold_product":"some product", "sold_at_price": 200}
{"index": {}}
{"sold_datetime": "2015-11-24T13:00:00.000Z", "sold_product":"some product", "sold_at_price": 200}
'
最后,让我们创建您需要的查询和聚合:
curl -XPOST localhost:9200/sales/sale/_search -d '{
"size": 0,
"query": {
"filtered": {
"filter": {
"range": {
"sold_datetime": {
"gt": "2015-11-24T12:15:00.000Z",
"lt": "2015-11-24T12:45:00.000Z"
}
}
}
}
},
"aggs": {
"sold_products": {
"terms": {
"field": "sold_product.raw",
"order": {
"total": "desc"
}
},
"aggs": {
"total": {
"sum": {
"field": "sold_at_price"
}
}
}
}
}
}'
如您所见,我们正在筛选sold_datetime
字段的特定日期间隔(11月24日12:15-12:45)。聚合部分在sold_product.raw
字段上定义terms
聚合,并且对于每个bucket,我们sum
定义sold_at_price
字段的值。
请注意,如果您有数百万个可能匹配的文档,为了使其具有性能,您需要首先应用最积极的过滤器,可能是运行查询的企业的id,或者在运行聚合之前排除尽可能多的文档的其他条件。
结果如下:
{
...
"aggregations" : {
"sold_products" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [ {
"key" : "some product",
"doc_count" : 2,
"total" : {
"value" : 300.0
}
}, {
"key" : "other product",
"doc_count" : 1,
"total" : {
"value" : 100.0
}
} ]
}
}
}