一、概要
分配给我的需求中,有一个需求是基于行为索引完成热度排行,我的想法就是通过聚合配合脚本语言完成该需求。
热度排行:一篇文档被收藏获得2分,被浏览获得1分,需要再行为表中聚合出得分最多的10篇文档,完成热度排行!
此处我们也看出需要对行为表进行聚合,字段不同的值 得到不同的分数,并且最后累加,获取总分,得出热度排行!
下面用简单示例解读如何完成这种需求的聚合
二、前置工作
a、创建行为索引
behavior代表行为码值(比如 1代表浏览 2代表收藏)
data_id代表行为对应的原文档的唯一标识
PUT /test_behavior_index
{
"mappings": {
"properties": {
"behavior": {
"type": "byte"
},
"data_id": {
"type": "keyword"
}
}
}
}
b、创建原文索引
就是一个测试的索引,没有特殊意义
为的就是有数据供上面的行为索引进行关联操作(收藏,浏览等)
PUT /test_index
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
}
}
}
}
c、插入测试数据
插入两个文档
POST /test_index/_doc/1
{
"title": "库里传",
"content": "历史上最伟大的球员之一......"
}
POST /test_index/_doc/2
{
"title": "追梦格林为人称赞的防守策应",
"content": "一个小个子为什么可以打5号位,又为什么可以串联球队....."
}
为两个文档插入行为数据
(id为1的文档:被浏览2次收藏2次)
(id为2的文档:被浏览1次)
# 此处可以用bluk批量插入
# 文档1 也就是库里传被收藏2次浏览2次
# 文档2 也就是追梦被浏览1次
POST /test_index/_doc/_bulk
{"index":{"_id":1}}
{"behavior":1,"data_id":"1"}
{"index":{"_id":2}}
{"behavior":1,"data_id":"1"}
{"index":{"_id":3}}
{"behavior":2,"data_id":"1"}
{"index":{"_id":4}}
{"behavior":2,"data_id":"1"}
{"index":{"_id":5}}
{"behavior":1,"data_id":"2"}
三、脚本聚合解决
解读该DSL:
首先通过一次termsAgg对data_id进行buckets聚合分组,旨在不同data_id的文档放入一个桶中!
第二次聚合为sumAgg的数字度量聚合,旨在将所有data_id的相同的文档的行为所得分数分累加
脚本解读:
其实非常简单的脚本。
如果我们的行为behavior字段为1(也就是浏览),那么就得到1分
如果我们行为behavior字段为2(收藏),那么就得到2分
但是值得注意的是,我们最好把参数放进params里,这样维护起来也相对简单,并且不会出现魔法值。
而且painess脚本不允许直接返回一个单体数字!所以更应该放进params中!
POST /test_behavior_index/_search
{
"query": {
"match_all": {}
},
"size": 0,
"aggs": {
"terms_agg": {
"terms": {
"field": "data_id",
"order": {
"sum_agg": "desc"
}
},
"aggs": {
"sum_agg": {
"sum": {
"script": {
"source": "if(doc['behavior'].value == 1){ return params['viewScore']} else if(doc['behavior'].value == 2) { return params['faviortScore']}",
"params": {
"viewScore": 1,
"faviortScore": 2
}
}
}
}
}
}
}
}
结果:
第一个文档被收藏2次,浏览两次获得 6分
第二个文档被浏览1次,获得1分
结果正确!
{
"took":9,
"timed_out":false,
"_shards":{
"total":1,
"successful":1,
"skipped":0,
"failed":0
},
"hits":{
"total":{
"value":6,
"relation":"eq"
},
"max_score":null,
"hits":[
]
},
"aggregations":{
"terms_agg":{
"doc_count_error_upper_bound":0,
"sum_other_doc_count":0,
"buckets":[
{
"key":"1",
"doc_count":4,
"sum_agg":{
"value":6
}
},
{
"key":"2",
"doc_count":1,
"sum_agg":{
"value":1
}
}
]
}
}
}
四、总结
相对比较简单,总体来说是一个桶聚合内部放入数字聚合,配合脚本对数字聚合得字段进行一个乘积控制!