和Hudi类似,Iceberg也提供了数据湖的功能,根据官网的定义,它是一个为分析大数据集开源的表存储格式,可以SQL表一样用Spark、Preso进行查询。Iceberg框架很好的解耦了数据计算与数据存储,计算引擎支持Spark、Flink和Hive等。本文第一部分将用Spark进行数据操作,后续再补充Flink操作部分。
Iceberg Schema可以通过HiveMetastore方式或者Hadoop文件方式进行管理,两种方式在处理Metadata的文件名时采用不同的方式,如果想直接通过Hive指定外部表是不行的。这种处理方式有些奇怪,不知道是不是因为我还没有看到这个设计背后的原因。
下面会通过Spark操作Iceberg的表和数据相关的怎删改操作,为了能够识别Iceberg,首先要启动SparkSession并配置好Iceberg的参数,参数是Metastore的位置,通过设置spark.sql.catalog.spark_catalog.type 来确定使用Hadoop文件还是Hive metastore,因为之后要使用Presto,这里用HiveMetastore来管理Iceberg的Metadata
val spark = SparkSession.builder().appName("aaa").
master("local[1]").
config("spark.sql.catalog.spark_catalog","org.apache.iceberg.spark.SparkSessionCatalog").
//使用Hive Metastore管理元数据
config("spark.sql.catalog.spark_catalog.type","hive").
config("spark.sql.catalog.hadoop_prod", "org.apache.iceberg.spark.SparkCatalog").
config("spark.sql.catalog.hadoop_prod.type", "hadoop").
config("spark.sql.catalog.hadoop_prod.warehouse", "hdfs://10.91.88.1:9000/tmp/iceberg").
config("spark.sql.catalog.hive_prod","org.apache.iceberg.spark.SparkCatalog").
config("spark.sql.catalog.hive_prod.type","hive").
config("spark.sql.catalog.hive_prod.uri", "thrift://10.91.88.1:9083").
getOrCreate()
查看历史快照
spark.sql(
s"""select * from $catalog.$dbTableName.snapshots
|""".stripMargin).show(false)
spark.sql(
s"""select * from $catalog.$dbTableName.history
|""".stripMargin).show(false)
Spark SQL创建表,并添加数据
spark.sql(
"""create table hive_prod.bbb.test (username string) using iceberg
|""".stripMargin)
spark.sql(
"""insert into hive_prod.bbb.test values ("user1"),("user2"),("user3")
|""".stripMargin)
spark.sql(
"""select * from hive_prod.bbb.test
|""".stripMargin).show(false)
添加字段成功之后,通过hive-cli可以验证新添加的字段
spark.sql(
"""alter table hive_prod.bbb.test add column address string, gender string
|""".stripMargin)
spark.sql("alter table hive_prod.bbb.test drop column city")
在Presto Server中添加Iceberg配置,/usr/lib/presto/etc/catalog/iceberg.properties
connector.name=iceberg
hive.metastore.uri=thrift://10.91.88.1:9083
查看表的Snapshot历史信息,Iceberg支持时间旅行,即历史查询,SparkSQL目前不支持TimeTravel,需要用Spark API进行调用。
spark.read
.option("snapshot-id", 10963874102873L)
.format("iceberg")
.load("path/to/table")
恢复到历史版本,需要同JavaAPI实现
val conf = new Configuration()
val warehousePath = "hdfs://10.91.88.1:9000/tmp/iceberg"
val catalog1 = new HadoopCatalog(conf, warehousePath)
val table = catalog1.loadTable(TableIdentifier.of("bbb", "test3"))
val sid = 4125943832602474030L
table.manageSnapshots().rollbackTo(sid).commit()
Iceberg合并小文件时并不会删除被合并的文件,Compact是将小文件合并成大文件并创建新的Snapshot。如果要删除文件需要通过Expire Snapshots来实现
Configuration conf = new Configuration();
String warehousePath = "hdfs://10.91.88.1:9000/tmp/iceberg";
HadoopCatalog catalog1 = new HadoopCatalog(conf, warehousePath);
Table table = catalog1.loadTable(TableIdentifier.of("bbb", "test8"));
Actions.forTable(table)
.rewriteDataFiles()
.targetSizeInBytes(100 * 1024 * 1024) // 100 MB
.execute();
历史快照是通过ExpireSnapshot来实现的,设置需要删除多久的历史快照
long tsToExpire = System.currentTimeMillis() - (1000*60*30 );
table.expireSnapshots()
.expireOlderThan(tsToExpire)
.commit();