让Druid实现事件设备数留存数的精准计算

我们在产品中有很多这样的指标需要计算:

  • 每天登陆的用户数(设备数)
  • 次日留存数(昨天的激活设备而且今天该设备还活跃),七日留存数,自定义日子的留存数。

诸如此类根据设备数来算的指标,如何实现?

我们之前是将设备ID转换为offset,再将offset转化为bitmap,并将其根据不同维度存在MySQL中。由于每天的写入和查询量太大,MySQL经受了严峻的考验。分库又面临着数据倾斜等各种问题。

我们后来准备将其迁入Druid中,但Druid天生并不支持这种运算。我们能不能增加一个bitmap的自定义扩展,使Druid也能够进行bitmap相关的聚合和查询运算呢?答案是可以的。

为了实现这个功能扩展,我们有两部分需要实现:

  1. 实现bitmap作为Druid的metric,存到Druid中。
  2. 定义规则,可以根据json查询bitmap计算以后的值,并返回客户端。
定义Module
  1. 定义BitmapDruidModule implements DruidModule
  2. 在src/main/resources目录下创建目录和文件:META-INF/services/io.druid.initialization.DruidModule
  3. 在以上文件内写入Module的定义类:io.druid.query.aggregation.bitmap.BitmapDruidModule

实现bitmap作为Druid的metric,存到Druid中

  • 实现BitmapCubeComplexMetricSerde extends ComplexMetricSerde。

        其中:
            1> TypeName: bitmapCube
            2> 实现其他相关方法。
                ComplexMetricExtractor getExtractor()
                ObjectStrategy getObjectStrategy()

                deserializeColumn(ByteBuffer byteBuffer, ColumnBuilder columnBuilder)

  • 将该Serde注册到ComplexMetrics中:
        ComplexMetrics.registerSerde(BITMAP_CUBE, new BitmapCubeComplexMetricSerde());
  • 实现BitmapCubeAggregator implements Aggregator
        主要实现aggregate()方法。
  • 实现 BitmapCubeAggregatorFactory extends AggregatorFactory
        类注解:@JsonTypeName("bitmapCube")
        实现combine等相关方法。
  • 在BitmapCubeDruidModule中的getJacksonModules() 方法里注册BitmapCubeAggregatorFactory类
      @Override
      public List<? extends Module> getJacksonModules() {
        return ImmutableList.of(
          new SimpleModule().registerSubtypes(
            new NamedType(io.druid.query.aggregation.bitmapcube.BitmapCubeCubeAggregatorFactory.class,     BITMAP_CUBE),
    ......
      }

定义查询规则

查询条件变为一个Queries的list,完整查询示例如下:

{
	"dataSource": "login_user",
	"queries": {
		"459068#SRC": {
			"filter": {
				"fields": [
					{
						"dimension": "dim1",
						"value": "BBDB6E271AFE4E5587892165205A20B1",
						"type": "selector"
					},
					{
						"dimension": "dim2",
						"value": "459068",
						"type": "selector"
					}
				],
				"type": "and"
			},
			"intervals": [
				"2018-03-06T00:00:00/2018-03-07T00:00:00"
			],
			"granularity": "all",
			"aggregations": [
				{
					"fieldName": "offsetBitmap",
					"name": "offsetBitmap",
					"type": "bitmapCube"
				}
			],
			"queryType": "groupBy",
			"limitSpec": {
				"type": "default"
			},
			"dataSource": "login_user"
		}
	},
	"postAggregations": [
		{
			"field": "459068#SRC",
			"func": null,
			"name": "459068",
			"fields": null,
			"type": "bitmapCubeSize"
		}
	],
	"intervals": [
		"2018-03-06T00:00:00/2018-03-07T00:00:00"
	],
	"queryType": "bitmapCube"
}

查询过程可使用线程池将每个子查询进行并行查询,然后将每个子查询的bitmap结果返回给Broker,然后Broker再根据Aggregator规则分别进行聚合,将聚合结果返回客户端。

然后根据Druid提供的接口实现Jersey的Resource,以及各种BitmapCubeQuery,Chest,Aggregator等各种类。

然后按照标准的Druid Extension进行部署。

此处不在详述。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值