Doris【数据模型】

news2024/10/1 5:41:46

一、数据模型简介

在 Doris 中,数据以表(Table)的形式进行逻辑上的描述。 一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。

Column 可以分为两大类:Key 和 Value。从业务角度看,Key 和 Value 可以分别对应维度列和指标列。Doris的key列是建表语句中指定的列,建表语句中的关键字'unique key'或'aggregate key'或'duplicate key'后面的列就是 Key 列,除了 Key 列剩下的就是 Value 列。

Doris 的数据模型主要分为3类:

  • Aggregate
  • Unique
  • Duplicate

下面我们分别介绍。

二、明细模型【Duplicate】

建表

CREATE TABLE order_info (
  order_date date NOT NULL COMMENT '下单日期',
  order_id int(11) NOT NULL COMMENT '订单id',
  buy_num tinyint(4) NULL COMMENT '购买件数',
  user_id int(11) NULL COMMENT '[-1223371, 1223371]',
  create_time datetime NULL COMMENT '创建时间',
  update_time datetime NULL COMMENT '更新时间'
) ENGINE=OLAP
DUPLICATE KEY(order_date, order_id)
COMMENT 'OLAP'
DISTRIBUTED BY HASH(order_id) BUCKETS 2
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

通过Flink Sql自带的datagen生成测试数据:

CREATE TABLE order_info_source (
    order_date DATE,
    order_id     INT,
    buy_num      INT,
    user_id      INT,
    create_time  TIMESTAMP(3),
    update_time   TIMESTAMP(3)
) WITH (
  'connector' = 'datagen',
  'rows-per-second' =  '10',
  'fields.order_id.min' = '99999',
  'fields.order_id.max' = '10001',
  'fields.user_id.min' = '10001',
  'fields.user_id.max' = '90001',
  'fields.buy_num.min' = '1',
  'fields.buy_num.max' = '200',
  'number-of-rows' = '10000'
)

datagen参数

'rows-per-second' = '1000' : 每秒发送1000条数据
'fields.order_id.min' = '99999': order_id最小值为99999
'fields.order_id.max' = '10001': order_id最大值为10001
'fields.user_id.min' = '10001': user_id最小值为10001
'fields.user_id.max' = '90001': user_id最大值为90001
'fields.buy_num.min' = '1': buy_num最小值为1
'fields.buy_num.max' = '200': buy_num最大值为200
'number-of-rows' = '10000': 共发送10000条数据, 不设置的话会无限量发送数据

参考文档:DataGen | Apache FlinkDataGen SQL Connector # Scan Source: Bounded Scan Source: UnBoundedThe DataGen connector allows for creating tables based on in-memory data generation. This is useful when developing queries locally without access to external systems such as Kafka. Tables can include Computed Column syntax which allows for flexible record generation.The DataGen connector is built-in, no additional dependencies are required.Usage # By default, a DataGen table will create an unbounded number of rows with a random value for each column.icon-default.png?t=N7T8https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/connectors/table/datagen/

注册Sink 表

CREATE TABLE order_info_sink (  
order_date DATE,  
order_id INT,  
buy_num INT,
user_id INT,
create_time TIMESTAMP(3),
update_time TIMESTAMP(3)
)  
WITH (
'connector' = 'doris',   
'fenodes' = '192.168.56.XXX:8030',   
'table.identifier' = 'test.order_info_example',   
'username' = 'test123',   
'password' = 'passwd123',   
'sink.label-prefix' = 'sink_doris_label_8'
)

写入Sink 表

insert into order_info_sink select * from order_info_source

通过mysql客户端查看Doris Sink表数据 

mysql> select * from  test.order_info_example limit 10;
+------------+----------+---------+---------+---------------------+---------------------+
| order_date | order_id | buy_num | user_id | create_time         | update_time         |
+------------+----------+---------+---------+---------------------+---------------------+
| 2024-02-22 |    30007 |      10 |   10560 | 2024-02-22 07:42:21 | 2024-02-22 07:42:21 |
| 2024-02-22 |    30125 |      16 |   17591 | 2024-02-22 07:42:26 | 2024-02-22 07:42:26 |
| 2024-02-22 |    30176 |      17 |   10871 | 2024-02-22 07:42:24 | 2024-02-22 07:42:24 |
| 2024-02-22 |    30479 |      16 |   19847 | 2024-02-22 07:42:25 | 2024-02-22 07:42:25 |
| 2024-02-22 |    30128 |      16 |   19807 | 2024-02-22 07:42:24 | 2024-02-22 07:42:24 |
| 2024-02-22 |    30039 |      13 |   18237 | 2024-02-22 07:42:28 | 2024-02-22 07:42:28 |
| 2024-02-22 |    30060 |      10 |   18309 | 2024-02-22 07:42:24 | 2024-02-22 07:42:24 |
| 2024-02-22 |    30246 |      18 |   10855 | 2024-02-22 07:42:24 | 2024-02-22 07:42:24 |
| 2024-02-22 |    30288 |      19 |   12347 | 2024-02-22 07:42:26 | 2024-02-22 07:42:26 |
| 2024-02-22 |    30449 |      17 |   11488 | 2024-02-22 07:42:23 | 2024-02-22 07:42:23 |
+------------+----------+---------+---------+---------------------+---------------------+
10 rows in set (0.05 sec)

三、Unique模型

当用户有数据更新需求时,可以选择使用Unique数据模型。Unique模型能够保证Key的唯一性,当用户更新一条数据时,新写入的数据会覆盖具有相同key的旧数据。

Unique模型提供了两种实现方式:

  • 读时合并(merge-on-read)。在读时合并实现中,用户在进行数据写入时不会触发任何数据去重相关的操作,所有数据去重的操作都在查询或者compaction时进行。因此,读时合并的写入性能较好,查询性能较差,同时内存消耗也较高。
  • 写时合并(merge-on-write)。在1.2版本中,我们引入了写时合并实现,该实现会在数据写入阶段完成所有数据去重的工作,因此能够提供非常好的查询性能。

Unique建表

CREATE TABLE IF NOT EXISTS example_db.example_tbl_unique
(
    `user_id` LARGEINT NOT NULL COMMENT "用户id",
    `username` VARCHAR(50) NOT NULL COMMENT "用户昵称",
    `city` VARCHAR(20) COMMENT "用户所在城市",
    `age` SMALLINT COMMENT "用户年龄",
    `sex` TINYINT COMMENT "用户性别",
    `phone` LARGEINT COMMENT "用户电话",
    `address` VARCHAR(500) COMMENT "用户地址",
    `register_time` DATETIME COMMENT "用户注册时间"
)
UNIQUE KEY(`user_id`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

 这是一个典型的用户基础信息表。这类数据没有聚合需求,只需保证主键唯一性。(这里的主键为 user_id + username)。

写时合并

CREATE TABLE IF NOT EXISTS example_db.example_tbl_unique_merge_on_write
(
    `user_id` LARGEINT NOT NULL COMMENT "用户id",
    `username` VARCHAR(50) NOT NULL COMMENT "用户昵称",
    `city` VARCHAR(20) COMMENT "用户所在城市",
    `age` SMALLINT COMMENT "用户年龄",
    `sex` TINYINT COMMENT "用户性别",
    `phone` LARGEINT COMMENT "用户电话",
    `address` VARCHAR(500) COMMENT "用户地址",
    `register_time` DATETIME COMMENT "用户注册时间"
)
UNIQUE KEY(`user_id`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"enable_unique_key_merge_on_write" = "true"
);

【注意】

  1. Unique表的实现方式只能在建表时确定,无法通过schema change进行修改。
  2. 旧的Merge-on-read的实现无法无缝升级到Merge-on-write的实现(数据组织方式完全不同),如果需要改为使用写时合并的实现版本,需要手动执行insert into unique-mow-table select * from source table.

四、聚合模型【Aggregate】 

CREATE DATABASE IF NOT EXISTS example_db;

CREATE TABLE IF NOT EXISTS example_db.example_tbl_agg1
(
    `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"
);

表中的列按照是否设置了 AggregationType,分为 Key (维度列) 和 Value(指标列)。没有设置 AggregationType 的,如 user_iddateage ... 等称为 Key,而设置了 AggregationType 的称为 Value

当我们导入数据时,对于 Key 列相同的行会聚合成一行,而 Value 列会按照设置的 AggregationType 进行聚合。 AggregationType 目前有以下几种聚合方式和agg_state:

  1. SUM:求和,多行的 Value 进行累加。
  2. REPLACE:替代,下一批数据中的 Value 会替换之前导入过的行中的 Value。
  3. MAX:保留最大值。
  4. MIN:保留最小值。
  5. REPLACE_IF_NOT_NULL:非空值替换。和 REPLACE 的区别在于对于null值,不做替换。
  6. HLL_UNION:HLL 类型的列的聚合方式,通过 HyperLogLog 算法聚合。
  7. BITMAP_UNION:BIMTAP 类型的列的聚合方式,进行位图的并集聚合。

数据导入

insert into example_db.example_tbl_agg1 values
(10000,"2017-10-01","北京",20,0,"2017-10-01 06:00:00",20,10,10),
(10000,"2017-10-01","北京",20,0,"2017-10-01 07:00:00",15,2,2),
(10001,"2017-10-01","北京",30,1,"2017-10-01 17:05:45",2,22,22),
(10002,"2017-10-02","上海",20,1,"2017-10-02 12:59:12",200,5,5),
(10003,"2017-10-02","广州",32,0,"2017-10-02 11:20:00",30,11,11),
(10004,"2017-10-01","深圳",35,0,"2017-10-01 10:00:15",100,3,3),
(10004,"2017-10-03","深圳",35,0,"2017-10-03 10:20:22",11,6,6);

 查询数据

 五、数据模型的选择建议

因为数据模型在建表时就已经u企鹅人,且无法修改。所以,选择一个何时的数据模型非常重要。

  1. Aggregate模型可以通过预聚合,极大的降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表查询场景。但是该模型对count(*)查询不是很友好。同时因为固定了Value列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。
  2. Unique模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用RollUp等预聚合带来的查询优势。对于聚合查询有较高性能需求的用户,推荐使用1.2版本加入的写时合并实现。
  3. Duplicate适合任意维度的ad-hoc查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有的列)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1484938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“视频剪辑新风尚:批量操作,背景虚化,聚焦视频主题!“

在数字时代,视频成为了最直观、最生动的信息表达方式。但是,面对大量的视频素材,如何快速有效地进行剪辑,突出视频主题,成为了许多创作者和编辑者的难题。 首先,我们要打开【视频剪辑高手】进入主页面之后…

【研发日记】Matlab/Simulink技能解锁(四)——在Simulink Debugger窗口调试

前言 见《【研发日记】Matlab/Simulink技能解锁(一)——在Simulink编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(二)——在Function编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug》 Block断点 前文在Simulink编辑窗口…

【蓝桥杯】错误票据

今天是2024年3月1号,蓝桥杯比赛还有一个月的时间,虽说自己不指望拿奖吧,但是还是有些莫i名的焦虑,这道题目都做不出来,感觉自己真的有点菜啊!但是还好啦,我觉得是因为我没有题感,慢慢…

(六)Dropout抑制过拟合与超参数的选择--九五小庞

过拟合 即模型在训练集上表现的很好,但是在测试集上效果却很差。也就是说,在已知的数据集合中非常好,再添加一些新数据进来效果就会差很多 欠拟合 即模型在训练集上表现的效果差,没有充分利用数据,预测准确率很低&a…

对缓冲区的初步认识——制作进度条小程序

对缓冲区的初步认识--进度条小程序 前言预备知识回车和换行的区别输出缓冲区/n 有清空输出缓冲区的作用stdout是什么?验证一切皆文件为什么是\n行刷新? 倒计时程序原理 代码实现为什么这里要强制刷新?没有会怎样?为什么是输出的是…

ABAP - SALV教程07 斑马纹显示和SALV标题

SALV设置斑马纹和标题 METHOD set_layout.DATA: lo_display TYPE REF TO cl_salv_display_settings. * 取得显示对象lo_display co_alv->get_display_settings( ).* 设置ZEBRA显示lo_display->set_striped_pattern( X ). * 设置Titlelo_display->set_list_he…

内存空间担保机制

什么是内存空间担保机制? 内存空间担保机制(Memory Space Guarantee)是垃圾回收(Garbage Collection)算法中的一种策略。它用于在进行垃圾回收过程(如Minor GC或Full GC)时,确保老年…

Linux创建,删除用户

Linux创建,删除用户 怎么登陆xshell创建用户设置密码 删除用户 我找了好久市面上的资料,我觉得写得不好,所以自己写一个 怎么登陆xshell ssh用户名ip地址 创建用户 adduser 用户名 设置密码 passwd 用户名 删除用户 userdel -r 用户…

【小尘送书-第十一期】编程的基石,开发的核心:《算法秘籍》

大家好,我是小尘,欢迎你的关注!大家可以一起交流学习!欢迎大家在CSDN后台私信我!一起讨论学习,讨论如何找到满意的工作! 👨‍💻博主主页:小尘要自信 &#x1…

利用小蜜蜂AI智能问答ChatGPT+AI高清绘图生成图文故事案例

利用小蜜蜂AI智能问答ChatGPTAI高清绘图生成图文故事案例 这段时间利用小蜜蜂AI网站做了一些编程、绘图以及数据分析方面的案例。再过几个月,我的大孙子就要出生了。我要用小蜜蜂AI智能问答和AI高清绘图为大孙子生成一个1-9的数字图文故事。 小蜜蜂AI网站可以扫如…

基于springboot+vue的高校教师科研管理系统

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

pdf如何压缩文件大小?pdf文件在线压缩方法介绍

在日常工作中,我们经常使用PDF文件进行传输和保存,然而,有时候我们会遇到过大的PDF文件,这不仅会导致传输困难,还会占用过多的设备空间,因此,我们需要对PDF压缩一下以便更轻松地传输和保存&…

基于springboot+vue的电商平台

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

Maven详细教程(很详细的)

一、maven概述 1.1、项目开发中的问题 1、我的项目依赖一些jar包,我把他们放在哪里?直接拷贝到项目的lib文件夹中?如果我开发的第二个项目还是需要上面的那些jar包,再把它们复制到我当前项目lib中?那如果现在是第三次了&#xf…

babylonjs入门-自由相机 FreeCamera

基于babylonjs封装的一些功能和插件 ,希望有更多的小伙伴一起玩babylonjs; 欢迎加群(点击群号传送):464146715 官方文档 中文文档 案例传送门 懒得打字 粘贴复制 一气呵成 ​

Mysql学习之MVCC解决读写问题

多版本并发控制 什么是MVCC MVCC (Multiversion Concurrency Control)多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之&#xff0…

node.js最准确历史版本下载

先进入官网:Node.js https://nodejs.org/en 嫌其他博客多可以到/release下载:Node.js,在blog后面加/release https://nodejs.org/en/blog/release/ 点击next翻页,同样的道理

在 Ubuntu 终端输出不同颜色、粗体、下划线或其他样式的字体

嗯。调试时总发现自己打印的调试信息太过普通、单调,于是乎…… Notice 要在终端实现字体的特殊样式,通常通过使用特殊的控制字符来实现,而不是通过某语言本身的功能来实现。 在大多数终端中,可以使用 ANSI 转义序列来设置字体的…

爬虫入门到精通_实战篇7(Requests+正则表达式爬取猫眼电影)_ 抓取单页内容,正则表达式分析,保存至文件,开启循环及多线程

1 目标 猫眼榜单TOP100:https://www.maoyan.com/board 2 流程框架 抓取单页内容:利用requests请求目标站点,得到单个网页HTML代码,返回结果。正则表达式分析:根据HTML代码分析得到电影名称,主演,上映时间,评分,图片…

overleaf上传到arxiv 参考文献无法引用(?)

记一下overleaf上传到arxiv的bug 参考文献无法引用(?) 因为需要上传bbl文件而不是bib 用overleaf生成bbl 另外需要将bbl和txt的文件名设置成一样的