您的位置:首页 > 产品设计 > UI/UE

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

2018-04-03 16:23 369 查看
我们在产品中有很多这样的指标需要计算:

每天登陆的用户数(设备数)
次日留存数(昨天的激活设备而且今天该设备还活跃),七日留存数,自定义日子的留存数。
诸如此类根据设备数来算的指标,如何实现?
我们之前是将设备ID转换为offset,再将offset转化为bitmap,并将其根据不同维度存在MySQL中。由于每天的写入和查询量太大,MySQL经受了严峻的考验。分库又面临着数据倾斜等各种问题。
我们后来准备将其迁入Druid中,但Druid天生并不支持这种运算。我们能不能增加一个bitmap的自定义扩展,使Druid也能够进行bitmap相关的聚合和查询运算呢?答案是可以的。
为了实现这个功能扩展,我们有两部分需要实现:

实现bitmap作为Druid的metric,存到Druid中。
定义规则,可以根据json查询bitmap计算以后的值,并返回客户端。
定义Module定义BitmapDruidModule implements DruidModule
在src/main/resources目录下创建目录和文件:META-INF/services/io.druid.initialization.DruidModule
在以上文件内写入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进行部署。
此处不在详述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Druid