hdfs数据写入hudi表并同步hive

将camus订阅的topics在hdfs上的某一天数据进行格式化并写为hudi表并同步到hive meatstore

引入相关环境
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 将camus订阅的topics在hdfs上的某一天数据进行格式化并写为hudi表并同步到hive meatstore
from __future__ import print_function
from pyspark.sql import SparkSession
from pyspark.sql import Row
from pyspark.sql.types import *
import json
import datetime
import sys
定义json解析函数
# 将topic的json解析为一层平铺的k-v
def json_format(item):
    new_item = {}
    for key,value in json.loads(item).items():
        if key == 'data':
            for k,v in json.loads(value).items():
                new_item[k] = v
        elif key == 'msg_data':
            for k,v in value.items():
                if k in ('video_size','material_id'):
                    new_item[k] = str(v)
                else:
                    new_item[k] = v
        else:
            new_item[key] = value
    return new_item
定义日期转换函数

hudi会通过字段值自动推断类型,yyyy-mm-dd类型的字段会被推断为时间戳timestamp,所以同步数据时,需要将必要的日期类字段从timestamp转换为yyyy-mm-dd格式

# UDF:将timestamp转换为yyyy-mm-dd格式 
def transform_date(df, column_names):
    for column_name in column_names:
        df = df.withColumn(column_name, from_unixtime(expr(f"{column_name}/1000"), "yyyy-MM-dd"))
    return df
读取hdfs的topic,进行hudi表同步

先读取topic的分区,然后把每个分区数据平铺为一层k-v格式的json文件并压缩存储到output_path路径下;
再将output_path路径下的json文件读取并解析为结构化的dataframe
配置hudi信息及同步hivemetastore的信息,将解析后的文件写入到hudi表,并同步到hive中
hive存储路径(即hudi表的路径)为hudi_table_base_path

if __name__ == '__main__':
    spark = SparkSession \
        .builder \
        .appName("ODS-DataFormat-ETL") \
        .getOrCreate()
    output_base_dir = "data_result_test" # 指定hudi表输出的基础路径,后续路径都需要放在此路径下
    partition = datetime.datetime.strptime(sys.argv[1], "%Y%m%d").strftime("%Y/%m/%d") # 指定hudi表的分区
	topic = 'qc_cost_plan'
	sc = spark.sparkContext
    rdd = sc.textFile("/data_source_test/camus/topics/%s/hourly/%s/*/*" %(topic,partition)) # topic对应在hdfs的数据读取路径(camus订阅的Kafka的topic,文件名称都是topic名称,分区为日期)
    rdd.persist() # 将rdd缓存到内存中,以便后续的操作可以更快地访问rdd
    output_path = '/%s/kscs_ods/%s/%s' %(output_base_dir,topic,partition) # topic平铺为一层json后的文件存储路径
    rdd.map(json_format).repartition(5).saveAsTextFile(output_path, 'org.apache.hadoop.io.compress.GzipCodec') # 将topic平铺为一层json,然后将文件重新分区为5个分区,分配到不同节点处理数据,最后将rdd保存到output_path指定的文件路径中,并使用'org.apache.hadoop.io.compress.GzipCodec'压缩算法对数据进行压缩
    df = spark.read.json(output_path) # 从hdfs的output_path路径中读取JSON格式的数据,并将其加载到DataFrame中。该DataFrame将自动推断JSON数据的模式,并将其转换为相应的列(将json结构化解析保存为dataframe)
    columns = ["data_date","start_date","end_date"] # 需要转换为yyyy-mm-dd格式的字段列表
    df = transform_date(df, columns) # 将timestamp转换为yyyy-mm-dd格式
    # hudi配置信息
    hudi_options = {
        'hoodie.table.name': topic, # 用于读取和写入的hudi表
        #'hoodie.datasource.write.recordkey.field': 'data_date,aweme_id,advertiser_id,', # 主键
        'hoodie.datasource.write.partitionpath.field': 'data_date',
        'hoodie.datasource.write.table.name': topic, # 用于写入的hudi表
        'hoodie.datasource.write.operation': 'upsert', # 写入模式
        'hoodie.datasource.write.precombine.field': 'add_time', # 预合并字段,写入的时候,若add_time以外的其他字段值都相同,则可以通过add_time将不同记录合并为单个记录(即单条数据被更新为最新数据,而非新增记录)
        'hoodie.upsert.shuffle.parallelism': 2, # 并行度
        'hoodie.insert.shuffle.parallelism': 2, # 并行度
        # 以下配置将Hudi表与Hive元存储进行同步,可以使Hudi表在Hive中可用
        "hoodie.datasource.hive_sync.enable": "true", # 写入Hudi表时自动将表与Hive元存储进行同步
        "hoodie.datasource.hive_sync.mode": "hms", # Hive元存储模式
        "hoodie.datasource.hive_sync.metastore.uris": "thrift://bigdata.hz003:9083", # Hive元存储的URI
        "hoodie.datasource.hive_sync.username": "",
        "hoodie.datasource.hive_sync.password": "",
        "hoodie.datasource.hive_sync.database": "kscs_ods",
        "hoodie.datasource.hive_sync.table": topic, # hudi同步到hivemetastore的表
        "hoodie.datasource.hive_sync.partition_fields":"data_date",
        "hoodie.datasource.hive_sync.partition_extractor_class":"org.apache.hudi.hive.MultiPartKeysValueExtractor" # 用这个分区提取器类来从Hudi表中提取分区信息,并将Hudi表正确地分区和同步到Hive中(这个分区提取器类支持使用多个分区键来对Hudi表进行分区)
    }
    if topic== 'qc_plan':
        hudi_options['hoodie.datasource.write.recordkey.field'] = 'data_date,aweme_id,advertiser_id,ad_id'
    hudi_table_base_path = '/%s/kscs_hudi_ods/%s' %(output_base_dir,topic)
    df.write.format("hudi").options(**hudi_options).mode("overwrite").save(hudi_table_base_path)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值