记录关于hive合并数据键值对的udf函数

文章描述了一个在工作场景中,如何使用ApacheHive和Spark的自定义用户定义函数(UDF)对数据进行处理,将指标数据按照指定规则合并,以减少IO消耗。代码示例展示了如何设计和使用Java编写的UDF来实现日期值替换和数据合并。
摘要由CSDN通过智能技术生成

项目场景:

在工作场景中,应用组需要页面上一个指标所显示的全部数据存放在一条数据中来减少数据传输所占用的io.
原本一条指标的数据的值一条是 (key, value) 类型
示例: xxxx1001 ,(20221203:8.96) xxxx1001 ,(20230128:5.46) 这样的. 分号前面是这条指标的业务时间,而后面的则是这条指标的值.
现在要修改成所有的值都合并在一个指标下面 例如:xxxx1001 ,(20221203:8.96,20230128:5.46) 这样.
根据数据组同事的讨论,现需要设计一个udf来满足需求.


代码示例

这个udf要满足一下几个需求:
1.满足新写入的日期的值替换老的日期的值
2.满足日期为空时不进行合并
3.把合并后的数据组合成一个值

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;


public class formastring extends UDF {
    public formastring(){}
    private static Logger logger = Logger.getLogger(formastring.class);

    public String evaluate(String strnew,String strold){
        if(StringUtils.isBlank(strold) && StringUtils.isBlank(strnew)   ){
            return "";
        } else if (StringUtils.isBlank(strold)) {
            return strnew;
        }else if (StringUtils.isBlank(strnew)) {
            return strold;
        }else  {
            Map collectold = null;
            try {
                Map<String, Double> collectnew = (Map<String, Double>) Arrays.asList(strnew.split(",")).stream().map((x) -> {
                    return x.split(":");
                }).collect(Collectors.toMap((e) -> {
                    return e[0];
                }, (e) -> {
                    return Double.parseDouble(e[1]);
                },(v1,v2) ->{
                    return v2;
                }));
                collectold= (Map<String, Double>) Arrays.asList(strold.split(",")).stream().map((x) -> {
                    return x.split(":");
                }).collect(Collectors.toMap((e) -> {
                    return e[0];
                }, (e) -> {
                    return Double.parseDouble(e[1]);
                }));
                collectold.putAll(collectnew);
            }catch (Exception e){

                logger.info("异常数据"+strnew+""+strold);
                e.printStackTrace();
                return "a";
            }
            return collectold.toString().replaceAll("([{}])", "");
        }
    }
    public static void main(String[] args){
        formastring udf =new formastring();
//        String strnew = "20220101:1.360X10^4,20220103:1";
//        String strold = "20220101:1,20220102:1";
          String strnew = "20221203:8.96,20230128:8.96";
          String strold = "20221204:105.000,20221203:106.000";
        System.out.println(udf.evaluate(strnew,strold));
    }
}

返回结果:

20230128=8.96, 20221204=105.0, 20221203=8.96

解决方案:

把这个udf导入进hive后,就可以直接使用了,取名为mapmerge函数.
下面是spark版的udf函数


import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.hadoop.shaded.org.eclipse.jetty.websocket.common.frames.DataFrame;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.sql.*;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;

public class sparkudf {

    public static void main(String[] args) {
        SparkSession spark = SparkSession.builder()
                .appName("MyUDF")
                .master("local[*]")
                .getOrCreate();

        // 创建示例数据
        StructType schema1 = DataTypes.createStructType(Arrays.asList(
                DataTypes.createStructField("key", DataTypes.StringType, true),
                DataTypes.createStructField("value", DataTypes.StringType, true),
                DataTypes.createStructField("data_source", DataTypes.StringType, true),
                DataTypes.createStructField("value_gather_time", DataTypes.StringType, true)
        ));
        Dataset<Row> data1 = spark.createDataFrame(Arrays.asList(
                RowFactory.create("puyi000001","20220101:1,20220102:1","wind","2023-03-20 10:57:38")
        ), schema1);

        StructType schema2 = DataTypes.createStructType(Arrays.asList(
                DataTypes.createStructField("key", DataTypes.StringType, true),
                DataTypes.createStructField("value", DataTypes.StringType, true)
        ));
        Dataset<Row> data2 = spark.createDataFrame(Arrays.asList(
                RowFactory.create("puyi000001","20220101:1.3"),
                RowFactory.create("puyi000001","20220104:2"),
                RowFactory.create("puyi000002","20220101:1")
        ), schema2);

        // 创建udf
        spark.udf().register("formastring", (String strnew, String strold) -> {
            if (strnew == null || strnew.isEmpty()) {
                return strold;
            } else if (strold == null || strold.isEmpty()) {
                return strnew;
            } else {
                Map<String, Double> collectnew = Arrays.stream(strnew.split(","))
                        .map(s -> s.split(":"))
                        .collect(Collectors.toMap(
                                a -> a[0], a -> Double.parseDouble(a[1])
                        ));
                Map<String, Double> collectold = Arrays.stream(strold.split(","))
                        .map(s -> s.split(":"))
                        .collect(Collectors.toMap(
                                a -> a[0], a -> Double.parseDouble(a[1])
                        ));
                collectold.putAll(collectnew);
                return collectold.entrySet().stream()
                        .sorted(Map.Entry.comparingByKey())
                        .map(e -> e.getKey() + ":" + e.getValue())
                        .collect(Collectors.joining(",", "", ""));
            }
        }, DataTypes.StringType);

        // 使用 UDF
        data1.createOrReplaceTempView("my_table");
        data2.createOrReplaceTempView("my_table2");
        Dataset<Row> result = spark.sql(
                "SELECT a.key, formastring(concat_ws(',', collect_list(a.value)), b.value) as result " +
                        "FROM my_table2 a LEFT JOIN my_table b ON a.key = b.key " +
                        "GROUP BY a.key, b.value"
        );
        result.show(100000, false);

        spark.stop();
    }

}
要使用自定义UDF函数的方式实现Hive中的CAST函数,需要按照以下步骤进行操作: 1. 创建一个自定义UDF函数类,该类需要继承Hive中的GenericUDF或者AbstractGenericUDF类。具体而言,如果你需要处理单个参数,则可以继承GenericUDF类,如果需要处理多个参数,则可以继承AbstractGenericUDF类。 2. 在类中实现evaluate()方法,该方法用于实现CAST函数的逻辑。该方法需要接收参数,并返回转换后的值。在方法中,你需要编写实现将传入参数转换成指定类型的代码。具体而言,你可以使用Java中的类型转换操作或者其他相关的转换函数来完成这个过程。 3. 将该类编译打包成jar文件,并上传到Hive的classpath中。 4. 在Hive中注册该自定义UDF函数。具体而言,你需要使用CREATE FUNCTION语句来创建该函数,并指定函数的名称、参数类型、返回类型等信息。例如,以下是一个示例代码: ``` CREATE FUNCTION my_cast AS 'com.example.MyCastUDF' USING JAR 'path/to/my-cast-udf.jar'; ``` 5. 在Hive中使用该自定义UDF函数。具体而言,你需要在SELECT语句中调用该函数,并将需要转换的参数作为函数的参数传入。例如,以下是一个示例代码: ``` SELECT my_cast(column_name AS target_type) FROM table_name; ``` 注意,这里的column_name是需要转换的列名,target_type是需要转换成的目标类型。你需要根据具体的情况进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值