表格存储服务 CLOUDTABLE-数据模型:Aggregate模型

时间:2025-01-10 15:12:55

Aggregate模型

以实际的例子来说明什么是聚合模型,以及如何正确的使用聚合模型。

  • 示例1:导入数据聚合

    假设业务有以下模式:

    表1 参数说明

    ColumnName

    Type

    AggregationType

    Comment

    user_id

    LARGEINT

    -

    用户 ID

    date

    DATE

    -

    数据导入日期

    city

    VARCHAR(20)

    -

    用户所在城市

    age

    SMALLINT

    -

    用户年龄

    sex

    TINYINT

    -

    用户性别

    last_visit_date

    DATETIME

    REPLACE

    用户最后一次访问时间

    cost

    BIGINT

    SUM

    用户总消费

    max_dwell_time

    INT

    MAX

    用户最大停留时间

    min_dwell_time

    INT

    MIN

    用户最小停留时间

    转换成建表语句,如下所示。

    CREATE TABLE IF NOT EXISTS demo.example_tbl
    (
        `user_id` LARGEINT NOT NULL COMMENT "用户id",
        `date` DATE NOT NULL COMMENT "数据灌入日期时间",
        `city` VARCHAR(20) COMMENT "用户所在城市",
        `age` SMALLINT COMMENT "用户年龄",
        `sex` TINYINT COMMENT "用户性别",
        `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",
        `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
        `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
        `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"
    )
    AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)
    DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
    PROPERTIES (
        "replication_allocation" = "tag.location.default: 1"
    );

    可以看到,这是一个典型的用户信息和访问行为的事实表。在一般星型模型中,用户信息和访问行为一般分别存放在维度表和事实表中。这里我们为了更加方便的解释Doris的数据模型,将两部分信息统一存放在一张表中。

    表中的列按照是否设置了AggregationType,分为Key(维度列)和Value(指标列)。没有设置AggregationType的,如user_id、date、age、sex称为Key,而设置了AggregationType的称为Value。

    当导入数据时,对于Key列相同的行会聚合成一行,而Value列会按照设置的AggregationType进行聚合。AggregationType目前有以下四种聚合方式:
    • SUM:求和,多行的Value进行累加。
    • REPLACE:替代,下一批数据中的Value会替换之前导入过的行中的Value。
    • MAX:保留最大值。
    • MIN:保留最小值。
      表2 原始数据

      user_id

      date

      city

      age

      sex

      last_visit_date

      cost

      max_dwell_time

      min_dwell_time

      10000

      2017-10-01

      A

      20

      0

      2017-10-01 06:00:00

      20

      10

      10

      10000

      2017-10-01

      A

      20

      0

      2017-10-01 07:00:00

      15

      2

      2

      10001

      2017-10-01

      A

      30

      1

      2017-10-01 17:05:45

      2

      22

      22

      10002

      2017-10-02

      B

      20

      1

      2017-10-02 12:59:12

      200

      5

      5

      10003

      2017-10-02

      C

      32

      0

      2017-10-02 11:20:00

      30

      11

      11

      10004

      2017-10-01

      D

      35

      0

      2017-10-01 10:00:15

      100

      3

      3

      10004

      2017-10-03

      D

      35

      0

      2017-10-03 10:20:22

      11

      6

      6

    我们假设这是一张记录用户访问某商品页面行为的表。我们以第一行数据为例,解释如下:

    表3 参数说明

    数据

    说明

    10000

    用户id,每个用户唯一识别id

    2017-10-01

    数据入库时间,精确到日期

    A

    用户所在城市

    20

    用户年龄

    0

    性别男(1 代表女性)

    2017-10-01 06:00:00

    用户本次访问该页面的时间,精确到秒

    20

    用户本次访问产生的消费

    10

    用户本次访问,驻留该页面的时间

    10

    用户本次访问,驻留该页面的时间(冗余)

    那么当这批数据正确导入到Doris中后,Doris中最终存储如下:

    表4 插入数据

    user_id

    date

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10000

    2017-10-01

    A

    20

    0

    2017-10-01 07:00:00

    35

    10

    2

    10001

    2017-10-01

    A

    30

    1

    2017-10-01 17:05:45

    2

    22

    22

    10002

    2017-10-02

    B

    20

    1

    2017-10-02 12:59:12

    200

    5

    5

    10003

    2017-10-02

    C

    32

    0

    2017-10-02 11:20:00

    30

    11

    11

    10004

    2017-10-01

    D

    35

    0

    2017-10-01 10:00:15

    100

    3

    3

    10004

    2017-10-03

    D

    35

    0

    2017-10-03 10:20:22

    11

    6

    6

    可以看到,用户10000只剩下了一行聚合后的数据。而其余用户的数据和原始数据保持一致。这里先解释下用户10000 聚合后的数据:

    前5列没有变化,从第6列 last_visit_date 开始:

    • 2017-10-01 07:00:00:因为last_visit_date列的聚合方式为REPLACE,所以2017-10-01 07:00:00替换了2017-10-01 06:00:00保存了下来。

      在同一个导入批次中的数据,对于REPLACE这种聚合方式,替换顺序不做保证。如在这个例子中,最终保存下来的,也有可能是2017-10-01 06:00:00。而对于不同导入批次中的数据,可以保证,后一批次的数据会替换前一批次。

    • 35:因为cost列的聚合类型为SUM,所以由20+15累加获得35。
    • 10:因为max_dwell_time列的聚合类型为MAX,所以10和2取最大值,获得10。
    • 2:因为min_dwell_time列的聚合类型为MIN,所以10和2取最小值,获得2。

      经过聚合,Doris中最终只会存储聚合后的数据。换句话说,即明细数据会丢失,用户不能够再查询到聚合前的明细数据了。

  • 示例2:保留,明细数据。

    接示例1,将表结构修改如下:

    表5 参数说明

    ColumnName

    Type

    AggregationType

    Comment

    user_id

    LARGEINT

    -

    用户 ID

    date

    DATE

    -

    数据导入日期

    timestamp

    DATETIME

    -

    数据导入时间,精确到秒

    city

    VARCHAR(20)

    -

    用户所在城市

    age

    SMALLINT

    -

    用户年龄

    sex

    TINYINT

    -

    用户性别

    last_visit_date

    DATETIME

    REPLACE

    用户最后一次访问时间

    cost

    BIGINT

    SUM

    用户总消费

    max_dwell_time

    INT

    MAX

    用户最大停留时间

    min_dwell_time

    INT

    MIN

    用户最小停留时间

    即增加了一列timestamp,记录精确到秒的数据导入时间。

    同时,将AGGREGATE KEY设置为AGGREGATE KEY(user_id, date, timestamp, city, age, sex)。

    导入数据如下:

    表6 原始数据

    user_id

    date

    timestamp

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10000

    2017-10-01

    2017-10-01 08:00:05

    A

    20

    0

    2017-10-01 06:00:00

    20

    10

    10

    10000

    2017-10-01

    2017-10-01 09:00:05

    A

    20

    0

    2017-10-01 07:00:00

    15

    2

    2

    10001

    2017-10-01

    2017-10-01 18:12:10

    A

    30

    1

    2017-10-01 17:05:45

    2

    22

    22

    10002

    2017-10-02

    2017-10-02 13:10:00

    B

    20

    1

    2017-10-02 12:59:12

    200

    5

    5

    10003

    2017-10-02

    2017-10-02 13:15:00

    C

    32

    0

    2017-10-02 11:20:00

    30

    11

    11

    10004

    2017-10-01

    2017-10-01 12:12:48

    D

    35

    0

    2017-10-01 10:00:15

    100

    3

    3

    10004

    2017-10-03

    2017-10-03 12:38:20

    D

    35

    0

    2017-10-03 10:20:22

    11

    6

    6

    那么当这批数据正确导入到Doris中后,Doris中最终存储如下:

    表7 数据结果

    user_id

    date

    timestamp

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10000

    2017-10-01

    2017-10-01 08:00:05

    A

    20

    0

    2017-10-01 06:00:00

    20

    10

    10

    10000

    2017-10-01

    2017-10-01 09:00:05

    A

    20

    0

    2017-10-01 07:00:00

    15

    2

    2

    10001

    2017-10-01

    2017-10-01 18:12:10

    A

    30

    1

    2017-10-01 17:05:45

    2

    22

    22

    10002

    2017-10-02

    2017-10-02 13:10:00

    B

    20

    1

    2017-10-02 12:59:12

    200

    5

    5

    10003

    2017-10-02

    2017-10-02 13:15:00

    C

    32

    0

    2017-10-02 11:20:00

    30

    11

    11

    10004

    2017-10-01

    2017-10-01 12:12:48

    D

    35

    0

    2017-10-01 10:00:15

    100

    3

    3

    10004

    2017-10-03

    2017-10-03 12:38:20

    D

    35

    0

    2017-10-03 10:20:22

    11

    6

    6

  • 示例3:导入数据与已有数据聚合。

    接示例1中的参数列,插入以下表中数据。

    表8 原始数据

    user_id

    date

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10000

    2017-10-01

    A

    20

    0

    2017-10-01 07:00:00

    35

    10

    2

    10001

    2017-10-01

    A

    30

    1

    2017-10-01 17:05:45

    2

    22

    22

    10002

    2017-10-02

    B

    20

    1

    2017-10-02 12:59:12

    200

    5

    5

    10003

    2017-10-02

    C

    32

    0

    2017-10-02 11:20:00

    30

    11

    11

    10004

    2017-10-01

    D

    35

    0

    2017-10-01 10:00:15

    100

    3

    3

    10004

    2017-10-03

    D

    35

    0

    2017-10-03 10:20:22

    11

    6

    6

    在导入一批新的数据:

    表9 新数据

    user_id

    date

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10004

    2017-10-03

    D

    35

    0

    2017-10-03 11:22:00

    44

    19

    19

    10005

    2017-10-03

    E

    29

    1

    2017-10-03 18:11:02

    3

    1

    1

    那么当这批数据正确导入到Doris中后,Doris中最终存储如下:

    表10

    user_id

    date

    city

    age

    sex

    last_visit_date

    cost

    max_dwell_time

    min_dwell_time

    10000

    2017-10-01

    A

    20

    0

    2017-10-01 07:00:00

    35

    10

    2

    10001

    2017-10-01

    A

    30

    1

    2017-10-01 17:05:45

    2

    22

    22

    10002

    2017-10-02

    B

    20

    1

    2017-10-02 12:59:12

    200

    5

    5

    10003

    2017-10-02

    C

    32

    0

    2017-10-02 11:20:00

    30

    11

    11

    10004

    2017-10-01

    D

    35

    0

    2017-10-01 10:00:15

    100

    3

    3

    10004

    2017-10-03

    D

    35

    0

    2017-10-03 11:22:00

    55

    19

    6

    10005

    2017-10-03

    E

    29

    1

    2017-10-03 18:11:02

    3

    1

    1

    可以看到,用户10004的已有数据和新导入的数据发生了聚合。同时新增了10005用户的数据。

    数据的聚合,在Doris中有如下三个阶段发生:

    • 每一批次数据导入的ETL阶段。该阶段会在每一批次导入的数据内部进行聚合。
    • 底层BE进行数据Compaction的阶段。该阶段,BE会对已导入的不同批次的数据进行进一步的聚合。
    • 数据查询阶段。在数据查询时,对于查询涉及到的数据,会进行对应的聚合。

    数据在不同时间,可能聚合的程度不一致。例如一批数据刚导入时,可能还未与之前已存在的数据进行聚合。但是对于用户而言,用户只能查询到聚合后的数据。即不同的聚合程度对于用户查询而言是透明的。用户需始终认为数据以最终的完成的聚合程度存在,而不应假设某些聚合还未发生。

support.huaweicloud.com/devg-cloudtable/cloudtable_01_0248.html