1. 概述
大家在之前使用Hive的时候知道 Hive 支持复杂的数据类型,Array、Map、STRUCT,特别是数组类型,在实际的开发和使用中经常遇到,而且使用也非常方便,Doris 在即将发布的 1.2 版本中也将提供数据类型的支持。
这里我们通过编译 master 分支的源码,提前尝鲜 Doris 的数组类型
具体 Doris 的编译方法请参照官方文档:https://doris.apache.org/zh-CN/docs/install/source-install/compilation
注意:
这里编译master分之的使用
docker pull apache/doris:build-env-ldb-toolchain-latest
Docker 镜像
具体的安装部署参照:https://doris.apache.org/zh-CN/docs/install/install-deploy
2. 开始使用
默认 Doris 数据现在是禁用的,我们需要通过下面的开关来设置启用
MySQL [(none)]> set enable_array_type=true;
Query OK, 0 rows affected (0.00 sec)
2.1 ARRAY<T>类型介绍
由T类型元素组成的数组,不能作为key列使用。目前支持在Duplicate模型的表中使用。其他数据模型暂时不支持
T支持的类型有:
BOOLEAN,
TINYINT,
SMALLINT,
INT,
BIGINT,
LARGEINT,
FLOAT,
DOUBLE,
DECIMAL,
DATE,
DATETIME,
CHAR,
VARCHAR,
STRING
2.2 创建表
这里我们创建一张班级测试表,里面包含class_id,class_name,student_ids(学生ID数组)
create table class_test(
class_id int ,
class_name varchar(20),
student_ids array<int>
) ENGINE=OLAP
DUPLICATE KEY(`class_id`,class_name)
COMMENT "OLAP"
DISTRIBUTED BY HASH(`class_name`) BUCKETS 2
PROPERTIES (
"replication_allocation" = "tag.location.default: 1",
"in_memory" = "false",
"storage_format" = "V2"
);
2.3 数据导入
这里导入的数组数据,数组列可以允许为NULL,数组内部元素也允许为NULL
2.3.1 Insert 数据插入:
MySQL [demo]> insert into class_test values (10001,'一年级一班',[10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011]);
Query OK, 1 row affected (0.03 sec)
{'label':'insert_fd3e529fed2e4a36-81e63bc50f2280ca', 'status':'VISIBLE', 'txnId':'7'}
MySQL [demo]> insert into class_test values (10002,'一年级二班',[20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20012]);
Query OK, 1 row affected (0.04 sec)
{'label':'insert_cda2c5d9305d457a-a46027b50d32eae3', 'status':'VISIBLE', 'txnId':'8'}
MySQL [demo]> insert into class_test values (10004,'四年级二班',[10002,null,10003]),(10005,'四年级三班',[10005,null,null]);
Query OK, 2 rows affected (0.04 sec)
{'label':'insert_a414305ef7494f34-9b89f058886080ec', 'status':'VISIBLE', 'txnId':'5'}
2.3.2 Stream load 导入数据
示例数据如下,保存成csv,这里使用tab分隔符
10006 六年级一班 [60002,60002,60003,null,60005]
10007 六年级二班 [70002,60002,70003,null,70005]
10008 六年级三班 [80002,60002,80003,null,80005]
导入
curl --location-trusted -u root: -T test.csv -H "column_separator:\t" -H "label:class_test" http://localhost:8030/api/demo/class_test/_stream_load
{
"TxnId": 9,
"Label": "class_test",
"TwoPhaseCommit": "false",
"Status": "Success",
"Message": "OK",
"NumberTotalRows": 3,
"NumberLoadedRows": 3,
"NumberFilteredRows": 0,
"NumberUnselectedRows": 0,
"LoadBytes": 159,
"LoadTimeMs": 65,
"BeginTxnTimeMs": 7,
"StreamLoadPutTimeMs": 22,
"ReadDataTimeMs": 0,
"WriteDataTimeMs": 8,
"CommitAndPublishTimeMs": 27
}
2.4 查询数据
2.4.1 查看所有数据
MySQL [demo]> select * from class_test;
+----------+-----------------+-------------------------------------------------------------------------------+
| class_id | class_name | student_ids |
+----------+-----------------+-------------------------------------------------------------------------------+
| 10004 | 四年级二班 | [10002, NULL, 10003] |
| 10005 | 四年级三班 | [10005, NULL, NULL] |
| 10001 | 一年级一班 | [10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011] |
| 10002 | 一年级二班 | [20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20012] |
| 10006 | 六年级一班 | [60002, 60002, 60003, NULL, 60005] |
| 10007 | 六年级二班 | [70002, 60002, 70003, NULL, 70005] |
| 10008 | 六年级三班 | [80002, 60002, 80003, NULL, 80005] |
+----------+-----------------+-------------------------------------------------------------------------------+
7 rows in set (0.00 sec)
2.4.2 计算student_ids 数组里的最大值
MySQL [demo]> select class_id, ARRAY_MAX(student_ids) from class_test;
+----------+--------------------------+
| class_id | array_max(`student_ids`) |
+----------+--------------------------+
| 10001 | 10012 |
| 10002 | 20012 |
+----------+--------------------------+
2 rows in set (0.02 sec)
2.4.3 判断字段student_ids是否包含10002
MySQL [demo]> select class_id, array_contains(student_ids,10002) from class_test;
+----------+--------------------------------------+
| class_id | array_contains(`student_ids`, 10002) |
+----------+--------------------------------------+
| 10001 | 1 |
| 10002 | 0 |
+----------+--------------------------------------+
2 rows in set (0.01 sec)
2.4.4 返回一个数组,包含所有在student_ids内但不在[10012,20011]内的元素,不包含重复项
MySQL [demo]> select class_id, array_except(student_ids,[10012,20011]) from class_test ;
+----------+-------------------------------------------------------------------------------+
| class_id | array_except(`student_ids`, ARRAY(10012, 20011)) |
+----------+-------------------------------------------------------------------------------+
| 10001 | [10001, 10002, 10003, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011] |
| 10002 | [20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20012] |
+----------+-------------------------------------------------------------------------------+
2 rows in set (0.01 sec)
2.4.5 查找10002 在student_ids 数组中第一次出现的位置/索引
MySQL [demo]> select class_id,array_position(student_ids, 10002) from class_test ;
+----------+--------------------------------------+
| class_id | array_position(`student_ids`, 10002) |
+----------+--------------------------------------+
| 10001 | 2 |
| 10002 | 0 |
+----------+--------------------------------------+
2 rows in set (0.01 sec)
2.4.6 去除student_ids数组中第二个值
-- 查找10002 在student_ids 数组中第一次出现的位置/索引
MySQL [demo]> select class_id,array_position(student_ids, 10002) from class_test ;
+----------+--------------------------------------+
| class_id | array_position(`student_ids`, 10002) |
+----------+--------------------------------------+
| 10001 | 2 |
| 10002 | 0 |
+----------+--------------------------------------+
2 rows in set (0.01 sec)
2.4.7 取出student_ids数组中第二个值
MySQL [demo]> select class_id,element_at(student_ids, 2) from class_test ;
+----------+------------------------------+
| class_id | element_at(`student_ids`, 2) |
+----------+------------------------------+
| 10001 | 10002 |
| 10002 | 20002 |
+----------+------------------------------+
2 rows in set (0.01 sec)
2.4.8 获取student_ids 数组长度
MySQL [demo]> select class_id,size(student_ids) from class_test ;
+----------+---------------------+
| class_id | size(`student_ids`) |
+----------+---------------------+
| 10001 | 12 |
| 10002 | 12 |
+----------+---------------------+
2 rows in set (0.01 sec)
--返回删除指定元素后的数组
MySQL [demo]> select class_id,array_remove(student_ids,10003) from class_test ;
+----------+--------------------------------------------------------------------------------------+
| class_id | array_remove(`student_ids`, 10003) |
+----------+--------------------------------------------------------------------------------------+
| 10001 | [10001, 10002, 10004, 10005, 10006, 10007, 10008, 10009, 10010, 10011, 10012] |
| 10002 | [20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20011, 20012] |
+----------+--------------------------------------------------------------------------------------+
2 rows in set (0.01 sec)
2.4.9 返回删除指定元素后的数组
MySQL [demo]> insert into class_test values (10004,'四年级二班',[10002,null,10003]),(10005,'四年级三班',[10005,null,null]);
Query OK, 2 rows affected (0.04 sec)
{'label':'insert_a414305ef7494f34-9b89f058886080ec', 'status':'VISIBLE', 'txnId':'5'}
2.5 数组列转行操作
我们在实际使用过程中,有很多行列转换的需求:行转列,列转行。下面我们来看看 Doris 中数组类型如何进行行列转换。
2.5.1 列转行
我们讲讲每个学生ID和班级ID,班级名称单独组成一行数据。
MySQL [demo]> SELECT class_id,class_name,student_id FROM class_test LATERAL VIEW explode(`student_ids`) student_id AS student_id WHERE class_id='10001';
+----------+-----------------+------------+
| class_id | class_name | student_id |
+----------+-----------------+------------+
| 10001 | 一年级一班 | 10001 |
| 10001 | 一年级一班 | 10002 |
| 10001 | 一年级一班 | 10003 |
| 10001 | 一年级一班 | 10004 |
| 10001 | 一年级一班 | 10005 |
| 10001 | 一年级一班 | 10006 |
| 10001 | 一年级一班 | 10007 |
| 10001 | 一年级一班 | 10008 |
| 10001 | 一年级一班 | 10009 |
| 10001 | 一年级一班 | 10010 |
| 10001 | 一年级一班 | 10011 |
+----------+-----------------+------------+
11 rows in set (0.00 sec)
2.5.2 行转列
这里我们讲每个学生所在的班级统一转成一个数组
MySQL [demo]> SELECT `stud_id`,collect_list(`class_name`) AS classes FROM (SELECT `class_name`,stud_id FROM `class_test` LATERAL VIEW explode(`student_ids`) stud_id AS stud_id) AS array_demo_row GROUP BY `stud_id`;
+---------+------------------------------------------------------------------------------------------------+
| stud_id | classes |
+---------+------------------------------------------------------------------------------------------------+
| 20010 | ['一年级二班'] |
| 20012 | ['一年级二班'] |
| 10011 | ['一年级一班'] |
| 70005 | ['六年级二班'] |
| 70003 | ['六年级二班'] |
| 10003 | ['四年级二班', '一年级一班'] |
| 10005 | ['四年级三班', '一年级一班'] |
| 20002 | ['一年级二班'] |
| 20004 | ['一年级二班'] |
| 70002 | ['六年级二班'] |
| 10010 | ['一年级一班'] |
| 10004 | ['一年级一班'] |
| 10002 | ['四年级二班', '一年级一班'] |
| 20005 | ['一年级二班'] |
| 20003 | ['一年级二班'] |
| 10009 | ['一年级一班'] |
| 80002 | ['六年级三班'] |
| 60003 | ['六年级一班'] |
| 20008 | ['一年级二班'] |
| 60005 | ['六年级一班'] |
| 20006 | ['一年级二班'] |
| 10001 | ['一年级一班'] |
| 10007 | ['一年级一班'] |
| 80005 | ['六年级三班'] |
| 80003 | ['六年级三班'] |
| 10008 | ['一年级一班'] |
| 60002 | ['六年级一班', '六年级一班', '六年级二班', '六年级三班'] |
| 20009 | ['一年级二班'] |
| 20007 | ['一年级二班'] |
| 20001 | ['一年级二班'] |
| 10006 | ['一年级一班'] |
| NULL | ['四年级二班', '四年级三班', '四年级三班', '六年级一班', '六年级二班', '六年级三班'] |
+---------+------------------------------------------------------------------------------------------------+
32 rows in set (0.01 sec)
3. Doris 数组函数介绍
Doris 针对数据类型提供了丰富的函数支持,下面我们简单介绍Doris的数组函数,具体可以参考官方文档(release之后再官网可以看到)
| 函数名称 | 函数介绍 | 备注 |
|---|---|---|
| ARRAY_AVG | 返回数组中所有元素的平均值 | |
| ARRAY_CONTAINS | 判断数组中是否包含value,1表示包含,0表示不包含 | 仅支持向量化引擎中使用 |
| ARRAY_DISTINCT | 数组去重 | 仅支持向量化引擎中使用 |
| ARRAY_EXCEPT | 是否包含所有在array1内但不在array2内的元素 | 仅支持向量化引擎中使用 |
| ARRAY_INTERSECT | 包含array1和array2的交集中的所有元素 | 仅支持向量化引擎中使用 |
| ARRAY_MAX | 返回数组中最大的元素 | |
| ARRAY_MIN | 返回数组中最小的元素 | |
| ARRAY_POSITION | 返回value在数组中第一次出现的位置/索引 | 仅支持向量化引擎中使用 |
| ARRAY_PRODUCT | 返回数组中所有元素的乘积 | |
| ARRAY_REMOVE | 返回移除所有的指定元素后的数组 | 仅支持向量化引擎中使用 |
| ARRAY_SORT | 返回按升序排列后的数组 | 仅支持向量化引擎中使用 |
| ARRAY_SUM | 返回数组中所有元素之和 | |
| ARRAY_UNION | 返回一个数组,包含array1和array2的并集中的所有元素,不包含重复项 | 仅支持向量化引擎中使用 |
| ARRAYS_OVERLAP | 判断left和right数组中是否包含公共元素 | 仅支持向量化引擎中使用 |
| ELEMENT_AT | 返回数组中位置为 position的元素 | 仅支持向量化引擎中使用 |
| SIZE (CARDINALITY) | 返回数组中元素数量 | 仅支持向量化引擎中使用 |
配合数组行列转换的函数
| 函数名称 | 函数说明 | 备注 |
|---|---|---|
| EXPLODE | 表函数,需配合 Lateral View 使用 ,将 ARRAY 列展开成多行 | |
| EXPLODE_OUTER | 表函数,需配合 Lateral View 使用 ,将 ARRAY 列展开成多行 | |
| COLLECT_LIST | ARRAY 行转列 | 仅支持向量化引擎中使用 |
| COLLECT_SET | ARRAY 行转列 | 仅支持向量化引擎中使用 |
4. 总结
这里我们简单介绍了 Doris 在 8 月底 9 月初即将发的 1.2 版本对数组类型的支持,通过写简单的示例给大家讲解了怎么使用 Doris 的数组类型,大家可以期待一下,新版本的发布,如果你想提前尝鲜,也可以自己编译 master 分支(强烈不建议在生产环境使用这个分支编译的版本),后续我们也将会出去其他复杂数据类型的支持,敬请期待。




