Hive-因精度丢失导致的 join 数据异常

一、问题复现

不知你是否遇到过 join 结果明显不匹配的情况,例如on t1.join_key = t2.join_key中两个join_key明显不相等,但 join 的结果却将其匹配在一起。今日博主在通过用户 id 关联获取用户信息时发现一个用户 id 可以在用户维表中匹配出若干条(用户维表不存在数据重复),如下:

-- 业务表
create table tmp_hz_perm.tmp_20240520_1
(id string
) stored as parquet;-- 用户维度表
create table tmp_hz_perm.tmp_20240520_2
(id   bigint,name string
) stored as parquet;

插入若干条数据

insert into tmp_hz_perm.tmp_20240520_1
values ('4268348961309240666');insert into tmp_hz_perm.tmp_20240520_2
values (4268348961309240666, 'user1'),(4268348961309241004, 'user2'),(3268348961319241004, 'user3');

模拟事故 sql

-- sql-1
select *
from tmp_hz_perm.tmp_20240520_1 t1
left join tmp_hz_perm.tmp_20240520_2 t2 on t1.id = t2.id;

我们期望的结果是返回user1,但实际情况却是匹配出多条数据

image-20240521162228139

有经验的小伙伴可能一眼就看出来 join 的问题,那就是两个join_key数据类型不一致,恭喜你成功找到了这个问题!!!那么对应的解决方案就是保持数据类型一致即可

-- sql-2
select *
from tmp_hz_perm.tmp_20240520_1 t1
left join tmp_hz_perm.tmp_20240520_2 t2 on cast(t1.id as bigint) = t2.id;

结束了吗???显然没有!我们还没有探寻这个问题的本质

二、本质分析

上面的现象可以总结出两点疑问:

  1. 数据不一致真的查询不出来数据吗
  2. 为什么会关联出一条完全不相干的数据

对于问题一,数据不一致是可以查询出来的,例如

-- sql-3
select * from tmp_hz_perm.tmp_20240520_2 where id = '4268348961309240666';+----------------------+----------------------+
|  tmp_20240520_2.id   | tmp_20240520_2.name  |
+----------------------+----------------------+
| 4268348961309240666  | user1                |
+----------------------+----------------------+
1 row selected (0.145 seconds)

回答问题二需要从执行计划出发

STAGE DEPENDENCIES:Stage-4 is a root stageStage-3 depends on stages: Stage-4Stage-0 depends on stages: Stage-3STAGE PLANS:Stage: Stage-4Map Reduce Local WorkAlias -> Map Local Tables:t2 Fetch Operatorlimit: -1Alias -> Map Local Operator Tree:t2 TableScanalias: t2Statistics: Num rows: 3 Data size: 6 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 UDFToDouble(id) (type: double)1 UDFToDouble(id) (type: double)Stage: Stage-3Map ReduceMap Operator Tree:TableScanalias: t1Statistics: Num rows: 1 Data size: 1 Basic stats: COMPLETE Column stats: NONEMap Join Operatorcondition map:Left Outer Join 0 to 1keys:0 UDFToDouble(id) (type: double)1 UDFToDouble(id) (type: double)outputColumnNames: _col0, _col4, _col5Statistics: Num rows: 3 Data size: 6 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: string), _col4 (type: bigint), _col5 (type: string)outputColumnNames: _col0, _col1, _col2Statistics: Num rows: 3 Data size: 6 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 3 Data size: 6 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeExecution mode: vectorizedLocal Work:Map Reduce Local WorkStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink

注意 hive 的执行计划中比我们想象中要多做一步UDFToDouble,其原因就是当两个关联键数据不一致时为了还可以进行关联,hive 将其 key 统一转换为Double,同时也可以看一下UDFToDouble的处理逻辑

public DoubleWritable evaluate(LongWritable i) {if (i == null) {return null;} else {doubleWritable.set(i.get());return doubleWritable;}
}public DoubleWritable evaluate(Text i) {if (i == null) {return null;} else {if (!LazyUtils.isNumberMaybe(i.getBytes(), 0, i.getLength())) {return null;}try {doubleWritable.set(Double.parseDouble(i.toString()));return doubleWritable;} catch (NumberFormatException e) {// MySQL returns 0 if the string is not a well-formed double value.// But we decided to return NULL instead, which is more conservative.return null;}}
}// doubleWritable.set(...)
public void set(double value) {this.value = value;
}

可以看出set入参均是 double,那么4268348961309240666在进行数据转换时一定会发生精度丢失(远超 double 的范围),下面的一个小 demo 可以很好的解释为什么会匹配出不相等的数据

package fun.uhope;import org.apache.hadoop.hive.ql.udf.UDFToDouble;
import org.apache.hadoop.hive.serde2.io.DoubleWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;public class Test {public static void main(String[] args) {String k1 = "4268348961309240666";long k2 = 4268348961309240666L;long k3 = 4268348961309241004L;long k4 = 3268348961309241004L;UDFToDouble uDFToDouble1 = new UDFToDouble();UDFToDouble uDFToDouble2 = new UDFToDouble();UDFToDouble uDFToDouble3 = new UDFToDouble();UDFToDouble uDFToDouble4 = new UDFToDouble();DoubleWritable v1 = uDFToDouble1.evaluate(new Text(k1));DoubleWritable v2 = uDFToDouble2.evaluate(new LongWritable(k2));DoubleWritable v3 = uDFToDouble3.evaluate(new LongWritable(k3));DoubleWritable v4 = uDFToDouble4.evaluate(new LongWritable(k4));System.out.println(v1);System.out.println(v2);System.out.println(v3);System.out.println(v4);System.out.println(v1.compareTo(v2));System.out.println(v1.compareTo(v3));System.out.println(v1.compareTo(v4));System.out.println((double) k2 == (double) k3);System.out.println((double) k2 == (double) k4);System.out.println(k2 == k3);}
}

结果如下:

image-20240521165433637

对于sql-2sql-3各位可以查看一下各自的执行计划就能明白为什么可以得到期望的结果

思考: 针对 hive join 过程中当数据类型不一致时采用UDFToDouble是否合理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/20051.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学生如何获取SOLIDWORKS产品技术支持

在当今日益复杂的学习环境中,技术软件如SOLIDWORKS已成为工程设计和制造类专业学生的重要工具。然而,面对这款功能强大的软件,学生们在使用过程中难免会遇到各种技术难题。那么,作为学生,我们该如何获取SOLIDWORKS产品…

imx6ull - 制作烧录SD卡

1、参考NXP官方的手册《i.MX_Linux_Users_Guide.pdf》的这一章节: 1、SD卡分区 提示:我们常用的SD卡一个扇区的大小是512字节。 先说一下i.MX6ULL使用SD卡启动时的分区情况,NXP官方给的镜像布局结构如下所示: 可以看到&#xff0c…

机器人控制系列教程之D-H参数建模法

机器人运动学的研究依赖于机器人的模型的建立,目前较为多见的两种方法分别是Denavit-Hartenberg建模法(简称:D-H建模法)。该方法时由Denavit和Hartenberg于19955年提出的一种为关节链中的每一个杆件建立一个坐标系的矩阵方法&…

LeetCode-131 分割回文串

LeetCode-131 分割回文串 题目描述解题思路C 代码 题目描述 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1: 输入:s “aab” 输出:[[“a”,“a”,“b”],…

HTML跳动的爱心

目录 写在前面 HTML简介 跳动的爱心 代码分析 运行结果

AI大模型简史:萌芽、沉淀、爆发!

近一年来,随着ChatGPT爆火,大模型热潮席卷全球并持续升温,国内越来越多的知名高校、科研院所和创新型企业加大研究力度,大模型技术不断迭代升级,模型能力不断加强,逐渐形成从底层算力、模型开发到行业应用的…

蓝桥杯--LCA1

树上前缀和LCA 暴力做法&#xff1a; 我们先把不删的sum维护出来&#xff0c;然后遍历跳过的点&#xff0c;假如a1,a2,a3&#xff0c;跳过2&#xff0c;那么答案就是sum-cost(a1,a2)-cost(a2,a3)cost(a1,a3). DFS暴力&#xff0c;下面是代码&#xff1a; #include<bits/s…

【Unity脚本】使用脚本操作游戏对象的组件

【知识链】Unity -> Unity脚本 -> 游戏对象 -> 组件 【知识链】Unity -> Unity界面 -> Inspector【摘要】本文介绍如何使用脚本添加、删除组件&#xff0c;以及如何访问组件 文章目录 引言第一章 游戏对象与组件1.1什么是组件&#xff1f;1.2 场景、游戏对象与组…

php使用openssl返回false报错0308010C

本地php使用openssl返回false, 但是在服务器上测试正常openssl_encrypt($jsonStr, DES-ECB, $key, OPENSSL_RAW_DATA, ); 查看错误 openssl_error_string(); error:0308010C:digital envelope routines::unsupported 原因是: 服务器上的openssl是1.1版本, 本地是3.0版本 通…

C++回调函数

#include <iostream> #include <functional> // 为了使用 std::function // 声明一个回调函数类型 typedef std::function<void()> Callback11;// 调用函数&#xff0c;它接受一个回调函数作为参数 void process(Callback11 callback123) {// 在这里执…

直播领域新宠—第三代大模型无人直播系统:提升销售业绩的秘密武器

随着科技的飞速发展和人们对智能化生活的追求&#xff0c;直播领域也迎来了革新性的突破。第三代大模型无人直播系统&#xff0c;作为直播领域的新宠&#xff0c;正以其独特的魅力和优势&#xff0c;成为提升销售业绩的秘密武器。 首先&#xff0c;第三代大模型无人直播系统具…

2024山软创新实训:软件系统架构

软件架构 本文着重介绍本应用&#xff1a;基于开源LLM的易学大模型软件系统的架构。在经过2个月的探索、选型、实验、开发后&#xff0c;我们团队终于把整个系统的各块拼图搭建了起来&#xff0c;现在剩下的是集成、评测、优化和部署的工作。 1. Distributed System 整个项目…

【Android】

hint在text显示提示内容 设置主键&#xff0c;在mainactivity // 获取SharedPreferences对象存放的用户名和密码&#xff0c;并设为相应组件的值 //指定key的值&#xff0c;及获取不到值时使用的默认值 String sName sp.getString("name", "unknown")…

媲美苹果、三星uwb芯片,飞睿智能UWB SIP芯片方案,创新无线传输、测距、精准定位新纪元

超宽带&#xff08;UWB&#xff09;技术作为一种新兴的无线通信技术&#xff0c;以其高精度定位、低功耗、高安全性和强抗干扰能力等优势&#xff0c;在全球范围内得到了广泛关注和快速应用。 2019 年&#xff0c;苹果iPhone11搭载UWB芯片&#xff0c;火极一时的AirDrop隔空投…

MODIS L1B数据规格介绍

1.MODIS 仪器概述 MODIS是EOS AM-1系列卫星的主要探测仪器&#xff0c;也是EOS Terra平台上唯一进行直接广播的对地观测仪器。MODIS是当前世界上新一代“图谱合一”的光学遥感仪器&#xff0c;具有36个光谱通道&#xff0c;分布在0.4-14um的电磁波谱范围内&#xff0c;波段范围…

Docker Hub 国内镜像源配置

Docker Hub 国内镜像源配置 Docker Hub 国内镜像源是指在国内境内提供 Docker 镜像服务的镜像源。由于国际网络带宽等问题&#xff0c;国内用户下载 Docker 镜像通常速度较慢。因此&#xff0c;为了解决这个问题&#xff0c;一些国内的公司和组织提供了 Docker 镜像的国内镜像…

MySQL--MHA高可用及读写分离

一、什么是高可用 1.企业级高可用标准&#xff1a;全年无故障时间 全年无故障时间全年故障时间具体时间99.9%0.1%525.6 minkeeplive双主 &#xff08;切换需要人为干预&#xff09;99.99%0.01%52.56 minMHA &#xff08;半自动化&#xff09;99.999%0.001%5.256 minPXC、MGR、…

解决3D模型变黑及贴图不显示的问题---模大狮模型网

在3D建模和渲染过程中&#xff0c;模型变黑或贴图不显示是常见的挑战之一。这不仅影响了模型的视觉效果&#xff0c;还可能导致后续的工作流程受阻。本文将针对这两个问题&#xff0c;提供详细的解决方法和步骤&#xff0c;帮助读者快速有效地解决问题。 一、检查并调整光照设置…

Day 8:1461. 检查一个字符串是否包含所有长度为 K 的二进制子串

Leetcode 1461. 检查一个字符串是否包含所有长度为 K 的二进制子串 给你一个二进制字符串 s 和一个整数 k 。如果所有长度为 k 的二进制字符串都是 s 的子串&#xff0c;请返回 true &#xff0c;否则请返回 false 。 截取每个长度为 k 的字符串&#xff0c;加入 Set 中&#x…

根据状态转移图实现时序电路 (三段式状态机)

看图编程 * ** 代码 module seq_circuit(input C ,input clk ,input rst_n,output wire Y ); reg [1:0] current_stage ; reg [1:0] next_stage ; reg Y_reg; //输出//第一段 &#xff1a; 初始化当前状态和…