Hudi(二)Spark操作Hudi

使用Spark操作Hudi表详细教程_spark sql操作hudi,2024年最新大数据开发小程序开发实例 【代码】使用Spark操作Hudi表详细教程_spark sql操作hudi,2024年最新大数据开发小程序开发实例。 阅读详情

1、Spark-shell读写Hudi

1.1、Spark-shell启动

// spark-shell for spark 3
spark-shell \
  --packages org.apache.hudi:hudi-spark3-bundle_2.12:0.10.0,org.apache.spark:spark-avro_2.12:3.1.2 \
  --conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer'
  
// spark-shell for spark 2 with scala 2.12
spark-shell \
  --packages org.apache.hudi:hudi-spark-bundle_2.12:0.10.0,org.apache.spark:spark-avro_2.12:2.4.4 \
  --conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer'
  
// spark-shell for spark 2 with scala 2.11
spark-shell \
  --packages org.apache.hudi:hudi-spark-bundle_2.11:0.10.0,org.apache.spark:spark-avro_2.11:2.4.4 \
  --conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer'

1.2、设置表名

        设置表名,基本路径和数据生成器

// spark-shell
import org.apache.hudi.QuickstartUtils._
import scala.collection.JavaConversions._
import org.apache.spark.sql.SaveMode._
import org.apache.hudi.DataSourceReadOptions._
import org.apache.hudi.DataSourceWriteOptions._
import org.apache.hudi.config.HoodieWriteConfig._

val tableName = "hudi_trips_cow"
val basePath = "file:///tmp/hudi_trips_cow"
val dataGen = new DataGenerator

1.3、数据写入

// spark-shell
val inserts = convertToStringList(dataGen.generateInserts(10))
val df = spark.read.json(spark.sparkContext.parallelize(inserts, 2))
df.write.format("hudi").
  options(getQuickstartWriteConfigs).
  option(PRECOMBINE_FIELD_OPT_KEY, "ts").
  option(RECORDKEY_FIELD_OPT_KEY, "uuid").
  option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath").
  option(TABLE_NAME, tableName).
  mode(Overwrite).
  save(basePath)

1.4、查询数据

// spark-shell
val tripsSnapshotDF = spark.
  read.
  format("hudi").
  load(basePath)
//load(basePath) use "/partitionKey=partitionValue" folder structure for Spark auto partition discovery
tripsSnapshotDF.createOrReplaceTempView("hudi_trips_snapshot")

spark.sql("select fare, begin_lon, begin_lat, ts from  hudi_trips_snapshot where fare > 20.0").show()
spark.sql("select _hoodie_commit_time, _hoodie_record_key, _hoodie_partition_path, rider, driver, fare from  hudi_trips_snapshot").show()

1.5、修改数据

// spark-shell
val updates = convertToStringList(dataGen.generateUpdates(10))
val df = spark.read.json(spark.sparkContext.parallelize(updates, 2))
df.write.format("hudi").
  options(getQuickstartWriteConfigs).
  option(PRECOMBINE_FIELD_OPT_KEY, "ts").
  option(RECORDKEY_FIELD_OPT_KEY, "uuid").
  option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath").
  option(TABLE_NAME, tableName).
  mode(Append).
  save(basePath)

1.6、增量查询

// spark-shell
// reload data
spark.
  read.
  format("hudi").
  load(basePath).
  createOrReplaceTempView("hudi_trips_snapshot")

val commits = spark.sql("select distinct(_hoodie_commit_time) as commitTime from  hudi_trips_snapshot order by commitTime").map(k => k.getString(0)).take(50)
val beginTime = commits(commits.length - 2) // commit time we are interested in

// incrementally query data
val tripsIncrementalDF = spark.read.format("hudi").
  option(QUERY_TYPE_OPT_KEY, QUERY_TYPE_INCREMENTAL_OPT_VAL).
  option(BEGIN_INSTANTTIME_OPT_KEY, beginTime).
  load(basePath)
tripsIncrementalDF.createOrReplaceTempView("hudi_trips_incremental")

spark.sql("select `_hoodie_commit_time`, fare, begin_lon, begin_lat, ts from  hudi_trips_incremental where fare > 20.0").show()

1.7、时间点查询

// spark-shell
val beginTime = "000" // Represents all commits > this time.
val endTime = commits(commits.length - 2) // commit time we are interested in

//incrementally query data
val tripsPointInTimeDF = spark.read.format("hudi").
  option(QUERY_TYPE_OPT_KEY, QUERY_TYPE_INCREMENTAL_OPT_VAL).
  option(BEGIN_INSTANTTIME_OPT_KEY, beginTime).
  option(END_INSTANTTIME_OPT_KEY, endTime).
  load(basePath)
tripsPointInTimeDF.createOrReplaceTempView("hudi_trips_point_in_time")
spark.sql("select `_hoodie_commit_time`, fare, begin_lon, begin_lat, ts from hudi_trips_point_in_time where fare > 20.0").show()

1.8、删除数据

// spark-shell
// fetch total records count
spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count()
// fetch two records to be deleted
val ds = spark.sql("select uuid, partitionpath from hudi_trips_snapshot").limit(2)

// issue deletes
val deletes = dataGen.generateDeletes(ds.collectAsList())
val df = spark.read.json(spark.sparkContext.parallelize(deletes, 2))

df.write.format("hudi").
  options(getQuickstartWriteConfigs).
  option(OPERATION_OPT_KEY,"delete").
  option(PRECOMBINE_FIELD_OPT_KEY, "ts").
  option(RECORDKEY_FIELD_OPT_KEY, "uuid").
  option(PARTITIONPATH_FIELD_OPT_KEY, "partitionpath").
  option(TABLE_NAME, tableName).
  mode(Append).
  save(basePath)

// run the same read query as above.
val roAfterDeleteViewDF = spark.
  read.
  format("hudi").
  load(basePath)

roAfterDeleteViewDF.registerTempTable("hudi_trips_snapshot")
// fetch should return (total - 2) records
spark.sql("select uuid, partitionpath from hudi_trips_snapshot").count()

1.9、覆盖数据

// spark-shell
spark.
  read.format("hudi").
  load(basePath).
  select("uuid","partitionpath").
  sort("partitionpath","uuid").
  show(100, false)

val inserts = convertToStringList(dataGen.generateInserts(10))
val df = spark.
  read.json(spark.sparkContext.parallelize(inserts, 2)).
  filter("partitionpath = 'americas/united_states/san_francisco'")
df.write.format("hudi").
  options(getQuickstartWriteConfigs).
  option(OPERATION.key(),"insert_overwrite").
  option(PRECOMBINE_FIELD.key(), "ts").
  option(RECORDKEY_FIELD.key(), "uuid").
  option(PARTITIONPATH_FIELD.key(), "partitionpath").
  option(TBL_NAME.key(), tableName).
  mode(Append).
  save(basePath)

// Should have different keys now for San Francisco alone, from query before.
spark.
  read.format("hudi").
  load(basePath).
  select("uuid","partitionpath").
  sort("partitionpath","uuid").
  show(100, false)

2、Spark写数据

        主要介绍,使用Delta Streamer工具从外部源甚至其他Hudi表中读取和更改的方法,以及使用Hudi数据源通过upserts加速Spark作业的方法。然后使用各种查询引擎来进行查询表数据。

2.1、Write Operations

   Delta Streamer工具提供3种不同的写入的操作方式

  1. Upsert:这是默认操作,输入数据时会通过索引判定为插入或更新。
  2. Insert:此操作与upsert类似,但是完全跳过索引,因此效率可能比upsert高的多,但也只适用于允许数据重复的场景。
  3. Bulk_Insert:upsert和insert操作都将数据保存到内存中,以更快的存储计算,因此在引导加载初始化表的时候会比较麻烦。那么大批插入的方式实现了基于排序的数据写入算法,可以很好地负载百TB的初始化负载。

2.2、Delta Streamer

   Hudi Delta Streamer提供了从不同来源(DFS或Kafka)读取数据的方法,具有以下功能

  1. 精准一次的从kafka消费数据,支持从Sqoop或HiveIncrementalPuller的输出或DFS文件的增量导入
  2. 支持手动创建arvo文件或者使用Confluent注册
  3. 支持传入数据类型有json、arvo或自定义类型
  4. 具有checkpoint检查点,回滚和恢复的功能

2.3、Spark DataFrame写数据

        1、引入hudi相关依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hudi</groupId>
        <artifactId>hudi-client</artifactId>
        <scope>provided</scope>
        <version>0.8.0</version>
        <type>pom</type>
    </dependency>
    <dependency>
        <groupId>org.apache.hudi</groupId>
        <artifactId>hudi-spark-bundle_2.12</artifactId>
        <scope>provided</scope>
        <version>0.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hudi</groupId>
        <artifactId>hudi-hadoop-mr-bundle</artifactId>
        <exclusions>
            <exclusion>
                <groupId>jackson-databind</groupId>
                <artifactId>com.fasterxml.jackson.core</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
            </exclusion>
        </exclusions>
        <version>0.8.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

        2、将Hudi目录编译好的hudi-hadoop-mr-bundle-0.8.0.jar,复制到hive的lib下让hive支持hudi,需要重启hive服务。

        3、实例代码(Spark读取数据写入Hive和Hudi)

package com.hudi

import org.apache.hudi.config.HoodieIndexConfig
import org.apache.hudi.hive.MultiPartKeysValueExtractor
import org.apache.hudi.index.HoodieIndex
import org.apache.spark.SparkConf
import org.apache.spark.sql.{SaveMode, SparkSession}

/**
 * @Author: Yuan Liu
 * @Description:
 * @Date: Created in 22:44 2021/12/21
 *
 *        Good Good Study Day Day Up
 */
object TableOperator {

  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setAppName("test_operator").setMaster("local[*]")
      .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
    insertData(sparkSession);
  }

  def insertData(sparkSession: SparkSession) = {
    import org.apache.spark.sql.functions._
    val commitTime = System.currentTimeMillis().toString //生成提交时间
    val resultDF = sparkSession.read.json("/user/atguigu/ods/member.log")
      .withColumn("ts", lit(commitTime)) //添加ts时间戳
      .withColumn("hudipartition", concat_ws("/", col("dt"), col("dn"))) //添加分区 两个字段组合分区
    Class.forName("org.apache.hive.jdbc.HiveDriver")
    resultDF.write.format("hudi")
      .option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, DataSourceWriteOptions.MOR_TABLE_TYPE_OPT_VAL) //选择表的类型 到底是MERGE_ON_READ 还是 COPY_ON_WRITE
      .option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "uid") //设置主键
      .option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "ts") //数据更新时间戳的
      .option(DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY, "hudipartition") //hudi分区列
      .option("hoodie.table.name", "member") //hudi表名
      .option(DataSourceWriteOptions.HIVE_URL_OPT_KEY, "jdbc:hive2://hadoop101:10000") //hiveserver2地址
      .option(DataSourceWriteOptions.HIVE_DATABASE_OPT_KEY, "default") //设置hudi与hive同步的数据库
      .option(DataSourceWriteOptions.HIVE_TABLE_OPT_KEY, "member") //设置hudi与hive同步的表名
      .option(DataSourceWriteOptions.HIVE_PARTITION_FIELDS_OPT_KEY, "dt,dn") //hive表同步的分区列
      .option(DataSourceWriteOptions.HIVE_PARTITION_EXTRACTOR_CLASS_OPT_KEY, classOf[MultiPartKeysValueExtractor].getName) // 分区提取器 按/ 提取分区
      .option(DataSourceWriteOptions.HIVE_SYNC_ENABLED_OPT_KEY, "true") //设置数据集注册并同步到hive
      .option(HoodieIndexConfig.BLOOM_INDEX_UPDATE_PARTITION_PATH, "true") //设置当分区变更时,当前数据的分区目录是否变更
      .option(HoodieIndexConfig.INDEX_TYPE_PROP, HoodieIndex.IndexType.GLOBAL_BLOOM.name()) //设置索引类型目前有HBASE,INMEMORY,BLOOM,GLOBAL_BLOOM 四种索引 为了保证分区变更后能找到必须设置全局GLOBAL_BLOOM
      .option("hoodie.insert.shuffle.parallelism", "12")
      .option("hoodie.upsert.shuffle.parallelism", "12")
      .mode(SaveMode.Append)
      .save("/user/my/hudi/hivetest")
  }

  /**
   * 修改数据,hudi支持行级更新
   */
  def updateData(sparkSession: SparkSession) = {
    //只查询20条数据,并进行修改,修改这20条数据的fullname值
    import org.apache.spark.sql.functions._

    val commitTime = System.currentTimeMillis().toString //生成提交时间
    val resultDF = sparkSession.read.json("/user/my/ods/member.log")
      .withColumn("ts", lit(commitTime)) //添加ts时间戳
      .withColumn("hudipartition", concat_ws("/", col("dt"), col("dn")))
      .where("uid >=0  and uid <20")
      .withColumn("fullname", lit("进行修改"))

    //改完数据之后,进行插入,表会根据DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY 主键进行判断修改
    //插入类型必须是append模 才能起到修改作用
    resultDF.write.format("hudi")
      .option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, DataSourceWriteOptions.MOR_TABLE_TYPE_OPT_VAL) //选择表的类型 到底是MERGE_ON_READ 还是 COPY_ON_WRITE
      .option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "uid") //设置主键
      .option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "ts") //数据更新时间戳的
      .option(DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY, "hudipartition") //hudi分区列
      .option("hoodie.table.name", "member") //hudi表名
      .option(DataSourceWriteOptions.HIVE_URL_OPT_KEY, "jdbc:hive2://hadoop101:10000") //hiveserver2地址
      .option(DataSourceWriteOptions.HIVE_DATABASE_OPT_KEY, "default") //设置hudi与hive同步的数据库
      .option(DataSourceWriteOptions.HIVE_TABLE_OPT_KEY, "member") //设置hudi与hive同步的表名
      .option(DataSourceWriteOptions.HIVE_PARTITION_FIELDS_OPT_KEY, "dt,dn") //hive表同步的分区列
      .option(DataSourceWriteOptions.HIVE_PARTITION_EXTRACTOR_CLASS_OPT_KEY, classOf[MultiPartKeysValueExtractor].getName) // 分区提取器 按/ 提取分区
      .option(DataSourceWriteOptions.HIVE_SYNC_ENABLED_OPT_KEY, "true") //设置数据集注册并同步到hive
      .option(HoodieIndexConfig.BLOOM_INDEX_UPDATE_PARTITION_PATH, "true") //设置当分区变更时,当前数据的分区目录是否变更
      .option(HoodieIndexConfig.INDEX_TYPE_PROP, HoodieIndex.IndexType.GLOBAL_BLOOM.name()) //设置索引类型目前有HBASE,INMEMORY,BLOOM,GLOBAL_BLOOM 四种索引 为了保证分区变更后能找到必须设置全局GLOBAL_BLOOM
      .option("hoodie.insert.shuffle.parallelism", "12")
      .option("hoodie.upsert.shuffle.parallelism", "12")
      .mode(SaveMode.Append)
      .save("/user/my/hudi/hivetest")
  }
}

注意:DataSourceWriteOptions.TABLE_TYPE_OPT_KEY:

        DataSourceWriteOptions.MOR_TABLE_TYPE_OPT_VAL。读时合并,会在hive产生2张表。

       DataSourceWriteOptions.COW_TABLE_TYPE_OPT_VAL。写时复制,在hive只产生1张表。

  • 如果表类型为copy on write,那么对应的hive里的建表会采用HoodieParquetInputFormat 格式行快照查询和增量查询
  • 如果表类型为Merge On Read类型,那么会得到两张表,分别以ro和rt结尾。rt结尾的表支持快照查询和增量查询,查询rt表将会查询表基本列数据和增量日志数据的合并视图,立马可以查询到修改后的数据。而ro表则只查询表中基本列数据并不会去查询增量日志里的数据。rt表采用HoodieParquetRealtimeInputFormat格式进行存储,ro表采用HoodieParquetInputFormat格式进行存储

2.4、两种类型表的比较

2.4.1、两张表支持的查询引擎及类型

  1. 快照查询,是指查询当前时间点的数据表,所以如果表是copy on write类型的表,那么直接进行查询就可以查看到修改后的数据。
  2. 如果是merge on read 表查询rt结尾的表为最新快照表,如果是使用spark sql查询,需要将spark.sql.hive.convertMetastoreParquet参数设置为false。查询ro结尾的表,则对应是读取优化查询,只查询最基本列数据,并不会看到被修改的数据。

2.4.2、快照查询与增量查询

1、快照查询(spark默认快照查询,也可以不指定类型)

spark
.read
.format("hudi")
.option(DataSourceReadOptions.QUERY_TYPE_OPT_KEY,DataSourceReadOptions.QUERY_TYPE_SNAPSHOT_OPT_VAL)
.load("/user/my/hudi/hivetest/*/*")
.where("uid>=0 and uid<20")
.show

2、增量查询

        hudi提供使用时间戳增量查询。指定查询类型为增量查询,并且传入时间戳,那么spark会查询时间戳以后的数据。

spark.read.format("hudi")
      .option(DataSourceReadOptions.QUERY_TYPE_OPT_KEY, DataSourceReadOptions.QUERY_TYPE_INCREMENTAL_OPT_VAL)
      .option(DataSourceReadOptions.BEGIN_INSTANTTIME_OPT_KEY, "20210805165813")
      .load("/user/my/hudi/hivetest/").show(40)

        DataSourceReadOptions.BEGIN_INSTANTTIME_OPT_KEY是开始时间戳,也对应有DataSourceReadOptions.END_INSTANTTIME_OPT_KEY结束时间戳,增量查询也可以给时间范围进行查询。(是大于开始时间戳)

2.5、Structured Streaming实时写Hudi

        实例代码

object StructuredStreamingTest {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf()
      .setAppName("test-app")
      .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
      .set("spark.sql.shuffle.partitions", "12")
    //     .setMaster("local[*]")
    val sparkSession = SparkSession.builder().config(sparkConf).getOrCreate()
    val df = sparkSession.readStream.format("kafka")
      .option("kafka.bootstrap.servers", "hadoop101:9092,hadoop102:9092,hadoop103:9092")
      .option("subscribe", "test2")
      .option("startingOffsets", "earliest")
      .option("maxOffsetsPerTrigger", "20000")
      .load()

    import sparkSession.implicits._
    val query = df.selectExpr("cast (value as string)").as[String]
      .map(item => {
        val jsonObj: JSONObject = JSON.parseObject(item)
        val userid = jsonObj.getString("userid").toLong;
        val username = jsonObj.getString("username")
        val age = jsonObj.getString("age").toInt
        val partition = jsonObj.getString("partition").toInt
        val ts = System.currentTimeMillis()
        new Model(userid, username, age, partition, ts)
      }).writeStream.foreachBatch { (batchDF: Dataset[Model], batchid: Long) =>
      batchDF.write.format("hudi")
        .option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, DataSourceWriteOptions.MOR_TABLE_TYPE_OPT_VAL) //选择表的类型 到底是MERGE_ON_READ 还是 COPY_ON_WRITE
        .option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "userid") //设置主键
        .option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "ts") //数据更新时间戳的
        .option(DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY, "partition") //hudi分区列
        .option("hoodie.table.name", "kafak_test_tabel") //hudi表名
        .option(DataSourceWriteOptions.HIVE_URL_OPT_KEY, "jdbc:hive2://hadoop101:10000") //hiveserver2地址
        .option(DataSourceWriteOptions.HIVE_DATABASE_OPT_KEY, "default") //设置hudi与hive同步的数据库
        .option(DataSourceWriteOptions.HIVE_TABLE_OPT_KEY, "kafak_test_tabel") //设置hudi与hive同步的表名
        .option(DataSourceWriteOptions.HIVE_PARTITION_FIELDS_OPT_KEY, "partition") //hive表同步的分区列
        .option(DataSourceWriteOptions.HIVE_PARTITION_EXTRACTOR_CLASS_OPT_KEY, classOf[MultiPartKeysValueExtractor].getName) // 分区提取器 按/ 提取分区
        .option(DataSourceWriteOptions.HIVE_SYNC_ENABLED_OPT_KEY, "true") //设置数据集注册并同步到hive
        .option(HoodieIndexConfig.BLOOM_INDEX_UPDATE_PARTITION_PATH, "true") //设置当分区变更时,当前数据的分区目录是否变更
        .option(HoodieIndexConfig.INDEX_TYPE_PROP, HoodieIndex.IndexType.GLOBAL_BLOOM.name()) //设置索引类型目前有HBASE,INMEMORY,BLOOM,GLOBAL_BLOOM 四种索引 为了保证分区变更后能找到必须设置全局GLOBAL_BLOOM
        .option("hoodie.insert.shuffle.parallelism", "12")
        .option("hoodie.upsert.shuffle.parallelism", "12")
        .mode(SaveMode.Append)
        .save("/ss/hudi/test-table")
    }.option("checkpointLocation", "/ss/checkpoint")
      .trigger(Trigger.ProcessingTime(5, TimeUnit.MINUTES))
      .start()
    query.awaitTermination()
  }
}
case class Model(userid: Long, username: String, age: Int, partition: Int, ts: Long)

3、并发控制

3.1、Hudi支持的并发控制

  • MVCC:Hudi的表操作,如压缩、清理、提交,hudi会利用多版本并发控制来提供多个表操作写入和查询之间的快照隔离。使用MVCC这种模型,Hudi支持并发任意数量的操作作业,并保证不会发生任何冲突。Hudi默认这种模型。
  • OPTIMISTIC CONCURRENCY:针对写入操作(upsert、insert等)利用乐观并发控制来启用多个写入器将数据写到同一个表中,Hudi支持文件级的乐观一致性,即对于发生在同一个表中的任何2个提交(写入),如果它们没有写入正在更改的重叠文件,则允许两个写入都成功。此功能处于实验阶段,需要用到Zookeeper或HiveMetastore来获取锁。

3.2、使用并发写

(1)如果需要开启乐观并发写入,需要设置以下属性
hoodie.write.concurrency.mode=optimistic_concurrency_control
hoodie.cleaner.policy.failed.writes=LAZY
hoodie.write.lock.provider=<lock-provider-classname>
(2)Hudi获取锁的服务提供两种模式使用zookeeper或者HiveMetaStore(选一种即可),相关zookeeper参数
hoodie.write.lock.provider=org.apache.hudi.client.transaction.lock.ZookeeperBasedLockProvider
hoodie.write.lock.zookeeper.url
hoodie.write.lock.zookeeper.port
hoodie.write.lock.zookeeper.lock_key
hoodie.write.lock.zookeeper.base_path
(3)相关HiveMetastore参数
hoodie.write.lock.provider=org.apache.hudi.hive.HiveMetastoreBasedLockProvider
hoodie.write.lock.hivemetastore.database
hoodie.write.lock.hivemetastore.table

实例:

.option("hoodie.cleaner.policy.failed.writes", "LAZY")
.option("hoodie.write.concurrency.mode", "optimistic_concurrency_control")
.option("hoodie.write.lock.provider","org.apache.hudi.client.transaction.lock.ZookeeperBasedLockProvider")
.option("hoodie.write.lock.zookeeper.url", "hadoop101,hadoop102,hadoop103")
.option("hoodie.write.lock.zookeeper.port", "2181")
.option("hoodie.write.lock.zookeeper.lock_key", "test_table")
.option("hoodie.write.lock.zookeeper.base_path", "/multiwriter_test")


 

Hudi集成Spark与hudi表的创建 阅读详情

相关推荐

2024年最新使用Spark操作Hudi表详细教程_spark读取hudi

【代码】2024年最新使用Spark操作Hudi表详细教程_spark读取hudi。

2401_84181070的博客 1544

基于 Ubuntu 玩转 Hudi Docker Demo (3)—— Spark写入和查询

本文介绍 Spark 写入和查询 Hudi 表。包括写入 CopyOnWrite 和 MergeOnRead 类型的 Hudi 表。查询包括 快照查询,读优化查询,增量查询。

修破立生 1445

湖仓一体介绍及spark操作hudi

湖仓一体介绍及spark操作hudi

chenlei0520的博客 1731

Spark——0基础入门数据湖Hudi的读写

【代码】Spark——数据湖Hudi的读写。

Carson073的博客 1588

Spark SQL 操作Apache Hudi

1. 添加jar包到spark的jar目录下 https://repo1.maven.org/maven2/org/apache/hudi/hudi-spark3.1.2-bundle_2.12/0.10.1/hudi-spark3.1.2-bundle_2.12-0.10.1.jar https://repo1.maven.org/maven2/org/apache/spark/spark-avro_2.12/3.1.2/spark-avro_2.12-3.1.2.jar 2. 重启spark集群 ./

JustinMars的博客 1536

PCIe控制器深度解析-RK3588 PCIe子系统核心模块探秘

本文深度解析了RK3588芯片中PCIe子系统的核心架构与功能模块。文章将PCIe控制器比作智能交通枢纽,详细阐述了RADM、XADM、CDM、eDMA等核心模块的工作原理,包括数据流管理、地址转换、DMA加速及电源管理。旨在帮助开发者和硬件工程师深入理解RK3588 PCIe控制器的内部机制,为驱动开发、性能优化和故障排查提供清晰的思路与实用指导。

weixin_29246195的博客 189

通过Spark读写Hudi

这个更全:Spark 增删改查 Hudi代码 一、使用Hudi环境准备 1.安装HDFS分布式文件系统:存储Hudi数据 Hadoop 2.8.0 首次格式化:hdfs namenode -format ./hadoop-daemon.sh start namenode ./hadoop-daemon.sh start datanode 测试:h...

qq_38304392的博客 3455

Netty源码分析系列之writeAndFlush()下

write()只会将数据只是发送到了ChannelOutboundBuffer 缓冲区中,还没有被发送到操作系统的套接字中只有当调用了 flush()方法后,才会真正将数据发送到套接字中。那么 flush()方法的源码又是如何执行的呢?

天堂的博客 1573

Spark操作Hudi之Scala操作入门

文章目录Scala操作入门1 进入scala1.1 使用shell2 读取数据3 写入数据4 增量查询5 删除数据 Scala操作入门 1 进入scala 1.1 使用shell spark-shell --packages org.apache.hudi:hudi-spark-bundle_2.11:0.8.0,org.apache.spark:spark-avro_2.11:2.4.4 --conf 'spark.serializer=org.apache.spark.serializer.KryoSe

韩江雪de 小屋 1059

Oracle OCP 19c 认证1Z0-083考试大纲(Oracle官方版)

Oracle Database: Managing Multitenant Architecture Ed 1 course

#真题在线# 1589

gem5 prefetcher

最近在gem5上做预取实验,添加自己的预取算法,这里采用hardware stream prefetcher , 修改了几个bug才给实验调试通过,发文记录下实验过程。 gem5上添加自己的预取算法步骤: (1)路径gem5-master/configs/common/Caches.py下,开启预取:class L1Cache(Cache): assoc = 2 tag_late

编程邦 3846

Hudi学习二:spark-shell操作Hudi

spark-shell操作hudi

NC_NE的博客 2834

RK3568 HDMI输出调试:分辨率切换与EDID解析

厂商信息(Vendor ID)显示器型号(Product ID)支持的分辨率列表色彩特性音频支持情况检查项方法HPD 信号EDID 读取当前模式TMDS 时钟PHY 状态。

小灰灰的博客 1491

使用Spark操作Hudi表详细教程

使用Spark操作hudi表教程和问题排错

Denny辉的博客 2529

为什么先进工艺需要check那么多corner?

那么hold slack = launch clock path delay + data path delay - capture_clock_path_delay = -capture_clock_path_delay,也就是说,capture clock path delay越大,hold越难满足。而且,我们在设计的时候,一般clock频率都会过约,所以是有较大的margin的。有的foundry还会对rc的取值范围进行了约束,如cworst_T,采用的是1.5 sigma的取值范围。

芯冰乐 2087

全面解读 SAP Business Data Cloud

SAP 在 2025 年初正式推出(简称BDC),它把、以及全新的统一封装为一项完全托管的 SaaS 服务,配套交付“语义层 + 数据产品 + 智能应用”三层能力,为企业构建真正贴近业务语境的 “Business Data Fabric”。这一方案不仅解决了跨系统数据碎片化、治理难及 AI 训练数据可信度低的问题,还为现有 BW 客户、S/4HANA以及第三方工作负载提供云上现代化路径和零拷贝数据共享机制。本文将围绕技术架构、核心组件、业务场景、迁移路线及未来展望展开,以 Henkel 等真实案例佐证。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 909

使用Spark操作Hudi表详细教程_spark sql操作hudi

编译输出的Spark Hudi依赖位于hudi/packaging/hudi-spark-bundle/target,将其中的hudi-spark3.x-bundle_2.12-0.xx.x.jar复制走备用。或者是在spark-defaults.conf中增加spark.hadoop.yarn.timeline-service.enabled=false。接着将Hudi编译之后的hudi-spark3.x-bundle_2.12-0.xx.x.jar复制到${SPARK_HOME}/jars目录中。

2401_84167046的博客 902

【四足机器人项目实战】波士顿spot四足机器人机工程设计及实现分析

主要介绍了波士顿spot机器人的发展历史、四足机器人的硬件系统及电机执行器组成包括硬件系统、关节电机执行器,机载传感器机处理器及电气连接等。概述了四足机器人规划控制、感知、定位及局部地图的相关算法方向。

qq_35635374的博客 4999

spark集成hudi详解

Hudi 支持用户自定义。

weixin_51981189的博客 2055

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Hudi学习03 -- Spark操作hudi(Spark-shell 和 PySpark)

spark操作hudi spark-shell pyspark

patrick_big_data的博客 3478

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Spark操作Hudi

pom文件如下 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/mav

寒暄的博客 2668

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

数据湖之Hudi(6):Hudi与Spark和HDFS的集成安装使用

目录 0. 相关文章链接 1. 编译Hudi源码 1.1. Maven安装 1.2. 下载并编译hudi 2. 安装HDFS 3. 安装Spark 4. 在spark-shell中运行hudi程序 主要介绍的Apache原生的Hudi、HDFS、Spark等的集成使用 0. 相关文章链接 大数据基础知识点 文章汇总 1. 编译Hudi源码 虽然对hudi的下载编译在博主的另一篇博文里有介绍,但这里是系统的介绍Hudi的体验使用,所以在介绍一遍。 1.1. Maven安装

yang_shibiao的博客 8260

Hudi学习三:Spark在IDEA环境操作hudi

IDEA操作Hudi

NC_NE的博客 2721

数据湖架构Hudi(二)Hudi版本0.12源码编译、Hudi集成spark、使用IDEA与spark对hudi表增删改查

数据湖架构Hudi(二)Hudi版本0.12源码编译、Hudi集成spark、使用IDEA与spark对hudi表增删改查

qq_44665283的博客 3504

使用Spark操作Hudi

开发环境: hadoop 2.7.6 hive 2.3.7 spark 2.4.5 1、pom文件 <repositories> <repository> <id>maven-ali</id> <url>http://maven.aliyun.com/nexus/content/groups/public//</url> <releases> <enabl

雾岛与鲸的博客 3539
上一篇: Hudi(一)基本介绍
下一篇: StarRocks(一)简介与手动部署
Yuan_CSDF
博客等级 码龄10年 169粉丝 130原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值