Skip to content

Latest commit

 

History

History
82 lines (56 loc) · 3.69 KB

一种自定义索引的方案.md

File metadata and controls

82 lines (56 loc) · 3.69 KB
date tags
2018-01-05
思考

最近在做实时计算相关的工作,在项目中用了一种基于mysql的索引方案。该方案是我同事设计的(找我同事的话可以私我)。使用该方案,可以实现多维度组合查询,以及简单按单维度分布查询的需求。作为一种敏捷的方案,查询速度和查询的方便程度都很好。

首先我把我们项目中实际的数据精简一下,假设经过计算之后的数据是下面这样的。

{
  metric: 'dau', // 指标
  value: 4,
  tags: { // 维度
    app: 'xxx',
    page: '/pay',
    province: 'liaoning',
    city: 'shenyang'
  }
}

现在想实现下面的功能:

  • 1,组合查询:
    • 通过app和page组合去查dau。
    • 通过app,province,city去查dau。
  • 2,简单的模糊查询:
    • 查看app为xxx,province为yyy下各个city的dau情况。

实现组合查询,只需要一张mysql表,字段如下。

id | metric | primary_hash | value

  • id:每张表都有的东西。
  • metric:指标。
  • value:指标值。需要注意的是这里的value是累加值,而不是结果。
  • hash:索引。

需要根据tag进行维度组合,所以首先需要定义一些维度组合:

[
  ['app', 'page'],
  ['app', 'province', 'city']
]

上面定义了需求中的两种维度组合,那么根据所定义的维度,我们需要录入两条数据:对于每一种维度组合,分别将它需要的维度拿出来,得到primary_hash值我们选择,后落到数据库,选择累加或者创建。

在查询的时候,计算对应的primary_hash用where语句就可以了。

实现模糊查询稍微有些绕

不过理解之后就感觉没那么复杂。

首先上面的表需要在加一个hash,取名为secondary_hash,那么表结构变为。

result表:id | metric | primary_hash | secondary_hash | value

  • secondary_hash:已知维度和模糊维度名组合的hash。

这里规定每个维度组合的最后一个维度名可以用来被模糊查询。如['app', 'province', 'city']可以对city进行模糊查询。

如要实现模糊查询,secondary_hash可以这样存。[{name: 'app', value: 'xxx'}, {name: 'province', value: 'liaoning'}, city]

这样要查询模糊维度时,只要使用指定的app,province值,指定需要模糊的维度city,就可以将这些值查出来。问题来了,每一条对应的city的值是什么?这里引入第二张表:

tag表beta: id | primary_hash | tag_name | tag_value

在计算过程中将需要模糊查询的tag_name的tag_value值以及对应的primary_hash存起来,这样对于使用secondary_hash取出来的每一条数据,就可以通过他的primary_hash以及需要的tag_name去查对应的tag_value。也就完成了一次模糊查询。

因为tag_name和tag_value的组合会被重复写入,为了复用数据,所以将上面的表拆成两张表,tag_name和tag_value写入另外一张表,通过联表进行关联即可。两张表的结构是这样的。

tagIndex表:id | primary_hash | tag_id

tag表:tag_id | tag_name | tag_value

result表中的每一项会在tagIndex表中对应多个tag_id,每个tag_id在tagIndex表里对应多个primary_hash。所以数据量大概是下面的关系(两边的n意义分离)。

如果维度爆炸的话,后面两张表的压力也很大,这也是做统计都要面对的问题。但我感觉这个方案还是比较能抗的。

这个方案看起来满足了一部分的需求,特点是很省磁盘,但是如果想实现更专业更复杂的需求,可能需要考虑使用es之类的方案。如果需求刚好相符,这将是一个小而美的方案 :)。