飙血推荐
  • HTML教程
  • MySQL教程
  • JavaScript基础教程
  • php入门教程
  • JavaScript正则表达式运用
  • Excel函数教程
  • UEditor使用文档
  • AngularJS教程
  • ThinkPHP5.0教程

hudi clustering 数据聚集(三 zorder使用)

时间:2021-12-04  作者:payapa  

目前最新的 hudi 版本为 0.9,暂时还不支持 zorder 功能,但 master 分支已经合入了(RFC-28),所以可以自己编译 master 分支,提前体验下 zorder 效果。

环境

1、直接下载 master 分支进行编译,本地使用 spark3,所以使用编译命令:

mvn clean package -DskipTests -Dspark3

2、启动 spark-shell,需要指定编译出来的 jar 路径:

spark-shell --jars /<path-to-hudi>/packaging/hudi-spark-bundle/target/hudi-spark3-域名-域名.0-域名  --conf \'域名alizer=域名域名Serializer\'

zorder commit 代码简略分析

相关配置

在 域名 中添加了 zorder 相关的配置,主要包括:

  • 该功能的使能(默认关闭)
  • 该功能使用的曲线类型(目前只实现 z-order,后续会实现 hilbert)
  • 曲线生成方式(包括 direct 和 sample,默认为 direct)
  • 数据跳过功能(默认开启)。

相关依赖

1、该配置在 HoodieClusteringConfig 定义,所以该功能的运行需要依赖 clustering ,会在聚集操作后对数据进行重新排序、写入。

2、该功能会生成自己的索引,索引记录的位置在 .hooie/.zindex 下,在 域名 中定义: public static final String ZINDEX_NAME = ".zindex";

3、该功能的索引列,由 域名.域名mns 决定,可指定多列,不同列用英文逗号分割,具体可参考 updateOptimizeOperationStatistics 函数。

相关限制

1、该功能目前支持 spark,暂时没有提供 Flink 和 Java 的实现。

2、在 zindex 中,只记录了最大值、最小值 和 null 值个数,具体可参见 saveStatisticsInfo 函数。

3、该功能支持的数据类型,具体可参见 createZIndexedDataFrameByMapValue 函数。

zvalue实现

1、direct 的 zvalue 生成: 域名

2、sample 的 zvalue 生成: 域名a

spark-shell 代码

import 域名.QuickstartUtils._
import 域名Conversions._
import 域名域名Mode._
import 域名.DataSourceReadOptions._
import 域名.DataSourceWriteOptions._
import 域名.域名ieWriteConfig._
import 域名.域名ieClusteringConfig._

val t1 = "t1"
val t2 = "t2"
val basePath = "file:///tmp/hudi_data/"
val dataGen = new DataGenerator(Array("2020/03/11"))

// 生成数据
var a = 0;
var ups = new Array[域名yList[String]](8)
var ups = new Array[域名[String]](8)
for (a <- 0 to 7) {
    ups(a) = convertToStringList(域名rateInserts(10000));
}

for (a <- 0 to 7) {
    val df = 域名(域名llelize(ups(a), 1));
    
    域名at("域名").
        options(getQuickstartWriteConfigs).
        option(PRECOMBINE_FIELD_OPT_KEY, "ts").
        option(RECORDKEY_FIELD_OPT_KEY, "uuid").
        option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath").
        option(TABLE_NAME, t1).
        // 每次写入的数据都生成一个新的文件		
        option("域名域名t", "0").
        mode(Append).
        save(basePath+t1);

    域名at("域名").
        options(getQuickstartWriteConfigs).
        option(PRECOMBINE_FIELD_OPT_KEY, "ts").
        option(RECORDKEY_FIELD_OPT_KEY, "uuid").
        option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath").
        option(TABLE_NAME, t2).
        // 每次写入的数据都生成一个新的文件		
        option("域名域名t", "0").
        // 每次操作之后都会进行clustering操作
        option("域名ne", "true").
        // 每4次提交就做一次clustering操作
        option("域名域名its", "8").
        // 指定生成文件最大大小
        option("域名.域名.域名s", "1400000").
        // 指定小文件大小限制,当文件小于该值时,可用于被 clustering 操作
        option("域名.域名.limit", "1400000").
        // 指定排序的列
        option("域名.域名mns", "begin_lat,end_lat").
        // 使能zorder
        option(域名(), true).
        mode(Append).
        save(basePath+t2);
}

// 创建临时视图
域名at("hudi").load(basePath+t1).createOrReplaceTempView("t1_table")
域名at("hudi").load(basePath+t2).createOrReplaceTempView("t2_table")

这里建立了2张表t1和t2,其中t1是普通的表,t2是使用了zorder排序的表。

共生成8组数据,总共80000条数据,生成对应8个数据文件(t2表修改文件的最大最小值,使其在数据合并之后仍然是8个文件,对应的配置是)域名.域名.域名s 和 域名.域名.limit。

针对 begin_lat 和 end_lat 列进行排序,使用默认的 direct 方式。

使用 inline 方式触发 clustering,在每 8 次提交进行一次 clustering。

现象及分析

1、在 t1 目录下,只有对应的 8 个 parquet 数据文件,在 t2 目录下,有 16 个 parquet 数据文件,其中 8 个是原始的数据文件,另外 8 个是 clustering 后新生成的数据文件。

2、在 t2 的 .hoodie 下 生成了 .zindex 目录:

可以使用 parquet-域名 对该文件进行查看:

file = 8f06528b-47ae-4b13-b41f-0a5c78851705-0_1-725-域名uet
begin_lat_minValue = 域名1371450402716
begin_lat_maxValue = 域名316799855066
begin_lat_num_nulls = 0
end_lat_minValue = 域名66719050410031
end_lat_maxValue = 域名245980998445
end_lat_num_nulls = 0

file = 53d66a45-d951-4e14-9344-ff187d12e9a5-0_0-725-域名uet
begin_lat_minValue = 域名37913420071E-6
begin_lat_maxValue = 域名301829548436
begin_lat_num_nulls = 0
end_lat_minValue = 域名34875439746E-6
end_lat_maxValue = 域名316614851375
end_lat_num_nulls = 0

file = a0663218-7da0-4ac4-8ffc-4616d2d44d1c-0_2-725-域名uet
begin_lat_minValue = 域名6873541740904
begin_lat_maxValue = 域名28795187336
begin_lat_num_nulls = 0
end_lat_minValue = 域名3249599535315
end_lat_maxValue = 域名5210011578595
end_lat_num_nulls = 0

file = 70192aaf-4766-441a-8781-ce381a54cf7c-0_3-725-域名uet
begin_lat_minValue = 域名3208286353262
begin_lat_maxValue = 域名482257584935
begin_lat_num_nulls = 0
end_lat_minValue = 域名6158207678606
end_lat_maxValue = 域名244932648992
end_lat_num_nulls = 0

file = ebc3017f-f93a-4366-bc20-3b9d86d73111-0_7-725-域名uet
begin_lat_minValue = 域名154203734088
begin_lat_maxValue = 域名920463384483
begin_lat_num_nulls = 0
end_lat_minValue = 域名295773327517
end_lat_maxValue = 域名604245270753
end_lat_num_nulls = 0

file = ec3f3bc8-3503-4642-b064-f93fa577ff83-0_6-725-域名uet
begin_lat_minValue = 域名433340037777
begin_lat_maxValue = 域名933816913421
begin_lat_num_nulls = 0
end_lat_minValue = 域名232553589945
end_lat_maxValue = 域名198848519347
end_lat_num_nulls = 0

file = 91f80f48-1837-4ee8-993c-56ffb9669e9e-0_4-725-域名uet
begin_lat_minValue = 域名5205774731387
begin_lat_maxValue = 域名255937189415
begin_lat_num_nulls = 0
end_lat_minValue = 域名0497130106802
end_lat_maxValue = 域名928793510746
end_lat_num_nulls = 0

file = 73d01fc5-e9b0-4216-afa5-86abffd082e4-0_5-725-域名uet
begin_lat_minValue = 域名222416743727
begin_lat_maxValue = 域名855548910661
begin_lat_num_nulls = 0
end_lat_minValue = 域名7377058575975
end_lat_maxValue = 域名7508767465637
end_lat_num_nulls = 0

以上只截取前两个数据。在该文件中,会对所有的 parquet 文件进行统计,统计的数据包括最大值、最小值和null个数,统计的列就是使用 域名.域名mns 指定的列。当 spark 进行查询时,就会使用这些条件来判断是否要读取该数据文件。

3、这里可以使用 begin_lat 和 end_lat 看下过滤效果:

a、sql("select count(*) from t2_table where begin_lat < 0.2 and end_lat < 0.5").show()

总共80000条数据,查询了37420条数据,最终得到数据:7951。

b、sql("select count(*) from t2_table where begin_lat < 0.2 and end_lat > 0.8").show()

总共80000条数据,查询了27473条数据,最终得到数据:3210。

c、sql("select count(*) from t2_table where begin_lat > 0.9 and end_lat < 0.2").show()

总共80000条数据,查询了49567条数据,最终得到数据:1600。

d、sql("select count(*) from t2_table where begin_lat > 域名 and end_lat < 域名").show()

总共80000条数据,查询了18235条数据,最终得到数据:81。

4、在 t1 表中,由于没有对 begin_lat 和 end_lat 做任何处理,所以同样查询以上4条 sql 时,都会读取 80000 条数据,而使用 zorder 之后,只分别读取了 37420,27473,49567,18235 条数据,过滤效果提升明显。

其实,不使能 zorder 功能,而只使用 clustering 的排序功能,也能做一些过滤,但由于本次实验中使用的数据分布较为均匀,所以虽然也可以对两个字段做排序,但基本上只会对第一个字段有较好的过滤效果,有兴趣的可以自己尝试一下。

标签:编程
湘ICP备14001474号-3  投诉建议:234161800@qq.com   部分内容来源于网络,如有侵权,请联系删除。