您可以使用scripted metric aggregations 做一些有趣的——也许是不可取的——事情。它们允许您定义针对您的文档运行的 map-reduce 脚本。当然,你可能会因此惹上麻烦。
但为了看看我能不能做到,我用您提供的数据建立了一个简单的单分片索引:
PUT /test_index
{"settings": {"number_of_shards": 1}}
POST /test_index/doc/_bulk
{"index":{"_id":1}}
{"num":1}
{"index":{"_id":2}}
{"num":4}
{"index":{"_id":3}}
{"num":2}
{"index":{"_id":4}}
{"num":4}
{"index":{"_id":5}}
{"num":5}
{"index":{"_id":6}}
{"num":3}
{"index":{"_id":7}}
{"num":3}
{"index":{"_id":8}}
{"num":2}
{"index":{"_id":9}}
{"num":1}
{"index":{"_id":10}}
{"num":4}
然后我可以像这样平均每两个文档:
POST /test_index/_search
{
"size": 0,
"aggs": {
"profit": {
"scripted_metric": {
"init_script" : "_agg['nums'] = []; _agg['avgs'] = [];",
"map_script" : "_agg.nums.add(doc['num'].value); if(_agg.nums.size() == 2){ _agg.avgs.add((_agg.nums[0] + _agg.nums[1])/2.0); _agg['nums'] = [];}",
"combine_script" : "return _agg.avgs",
"reduce_script" : "return _aggs"
}
}
}
}
...
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 10,
"max_score": 0,
"hits": []
},
"aggregations": {
"profit": {
"value": [
[
2.5,
3,
4,
2.5,
2.5
]
]
}
}
}
它似乎不尊重查询中的排序顺序,尽管据我所知结果是确定性的。
我在这里所做的仅适用于单个分片;如果你想修改它足够长的时间,你可能会以某种方式概括它。
另外,大胖免责声明:在生产中这样做可能不是一个好主意。在您可能因内存不足错误导致集群崩溃之前,您需要先在小型数据集上测试此类事情。此外,仅当您的集群未对严重的 Internet 开放时才使用脚本。
这是我用来玩它的一些代码:
http://sense.qbox.io/gist/c31f089e63200127fd9ca09992004db8bb11b890