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

卷积码和Turbo码

通信原理相关博文目录:目录我们常在移动通信中遇到的卷积码就是一种非分组码,卷积码和信号处理中的卷积运算有关系吗?是不是就是信号处理中的卷积运算,先看看编码器的编码原理再说:下面是一个比较实用的卷积码编码器:它有三个移位寄存器D0,D1,D2和三个模2加法器,以及一个旋转开关组成,编码前,先将各级移位寄存器清零:现在假设输入的信息码元是1101:当输入的第一个码元为1时,三个模2加法器计算的结果都为...

Reborn Lee 2万+

通过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

电化学阻抗谱(EIS)在锂离子电池中的应用

摘要电化学阻抗谱(electrochemical impedance spectroscopy, EIS)是一种重要的电化学测试方法,在锂离子电池动力学反应机理研究及动力学参数测量等方面具有广泛的应用。在锂离子电池运行过程中,各反应步骤的动力学参数及时间常数不同,而EIS可以在较宽的频率范围内对体系施加小幅正弦激励信号,使得在特定频率下突出特定时间常数的电极过程,从而将复杂的电极过程分离,实现单一电极过程动力学的分析。通过对交流阻抗信息的研究,也可以为锂离子电池及其他电池的应用与管理、电化学过程设计及电极材

qiushireader的博客 2655

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

NSFC结题报告下载脚本失效?3步教你手动修复下载按钮问题(2024最新版)

针对NSFC官网域名变更导致结题报告下载脚本失效的问题,本文提供了详细的手动修复指南。通过三步操作,教你如何修改用户脚本的域名匹配规则,恢复下载按钮功能,确保NSFC结题报告下载器能继续高效工作。

vscode6remote的博客 753

【水下小目标检测】SWIPENet与样本重加权:应对模糊与噪声的深度学习策略

本文深入探讨了水下小目标检测的挑战与解决方案,重点介绍了SWIPENet网络架构与IMA样本重加权算法。通过空洞卷积模块、特征金字塔重构和多尺度预测机制,SWIPENet有效提升了模糊目标的检测精度。结合Invert Multi-Class Adaboost算法,系统性地解决了水下环境中的样本不均衡问题,在URPC数据集上实现了48.8%的mAP,特别适合海洋生物检测等应用场景。

weixin_29057163的博客 346

Hudi学习二:spark-shell操作Hudi

spark-shell操作hudi

NC_NE的博客 2834

Pyinstaller 打包 Pyzbar 时缺失 DLL 文件的排查与修复指南

本文详细解析了使用Pyinstaller打包Pyzbar库时,因缺失关键DLL文件导致程序闪退的常见问题。文章提供了从问题复现、错误诊断到最终修复的完整解决方案,核心在于通过修改.spec配置文件,手动将缺失的libzbar-64.dll等文件添加到打包过程中,确保生成的可执行文件能独立运行。

wdx012345的博客 504

使用Spark操作Hudi表详细教程

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

Denny辉的博客 2529

Linux(31)Rockchip RK3568 Ubuntu22.04上部署 Docker: 问题与解决方案

本博客在总结这些问题及其解决方案,为遇到类似问题的兄弟提供参考,如果我后续有碰到其他Docker 问题也会在此更新补充。

我其实什么都不会 1646

揭秘LLM如何预测下一个词

Transformer结构的大语言模型(LLM)通过自回归训练学习预测下一个词汇,其核心能力源自权重矩阵的动态优化。自注意力层的Wq/Wk/Wv矩阵捕捉语义关联,前馈网络的W1/W2矩阵进行非线性特征提取,LM Head的W_{lm}矩阵将语义映射到词汇概率。训练过程中,这些矩阵通过反向传播不断调整,最终使模型能够根据上下文(如"我"→"爱")生成合理的后续词汇。这种基于矩阵变换的数学机制是LLM智能生成文本的本质原因。(150字)

ZhangJiqun&191cm&85kg 376

使用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

在 SAP S/4HANA 本地部署和私有云里预览 RAP Travel App:为什么 ADT 发不出去,以及如何用 /IWFND/V4_ADMIN 正确发布 OData V4 Service

在SAP S/4HANA On-Premise/Private Cloud环境中,通过ADT直接发布RAP服务的本地端点常会失效。这是因为系统治理策略要求必须通过SAP Gateway Foundation(事务码/IWFND/V4_ADMIN)发布Service Group,而非开发者本机测试模式。本文详解了该流程的必要性:Service Group是OData V4服务的发布单元,涉及后端登记(/IWBEP/V4_ADMIN)和前端发布(/IWFND/V4_ADMIN)两个环节。提供了从ADT跳转SAP

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

spark集成hudi详解

Hudi 支持用户自定义。

weixin_51981189的博客 2055

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

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

spark操作hudi spark-shell pyspark

patrick_big_data的博客 3478

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

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

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

数据湖之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的博客 8261

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、付费专栏及课程。

余额充值