1.hive和spark查询不一致(parquet版本问题)

org.apache.parquet.io.ParquetDecodingException: Can not read value at 0 in block -1 in file xxx spark产出的数据hive查询异常报错Can not read value at 0 in block -1 in file xxx hive查询:
Demo-查询不一致(持续更新) - 图1

spark查询:
Demo-查询不一致(持续更新) - 图2
解决方式:spark产出数据时添加参数conf spark.sql.parquet.writeLegacyFormat=true

原因:
设置为true时,数据会以Spark1.4和更早的版本的格式写入。比如decimal类型的值会被以Apache Parquet的fixed-length byte array格式写出,该格式是其他系统例如Hive、Impala等使用的。
设置为false时,会使用parquet的新版格式。例如,decimals会以int-based格式写出。如果Spark SQL要以Parquet输出并且结果会被不支持新格式的其他系统使用的话,需要设置为true。

2.impala查询和spark不一致(json表支持问题)

用户业务sql使用impala和spark查询的数据量不一致,impala数据多
解决方式:暂时以spark查询的结果为准。

spark查询:

Demo-查询不一致(持续更新) - 图3

impala查询:

Demo-查询不一致(持续更新) - 图4

原因:
表为json表 ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'

社区impala目前是不支持读,开发怀疑有bug,目前建议等社区JSON表功能,先用spark读。

3.spark和impala执行不一致的问题(函数使用姿势有区别)

impala:
Demo-查询不一致(持续更新) - 图5

spark:
Demo-查询不一致(持续更新) - 图6

原因:
如报错,spark的isnull函数不允许传两个参数。也咨询了spark开发,isnull 只接收一个参数,这里同一个函数,impala和spark有区别,会对用户造成困扰。类似的函数使用姿势不同的问题。希望能有一个说明手册,方便用户使用。

4. 修改字段查询null(参数问题)

直接使用alter table对hive表修改字段名称,修改后hive和spark和impala均为null
原因:
hive和spark和impala均是按列名查parquet文件,修改列名后目前查询均为null解决方式如下 hive查询解决方式
执行ALTER TABLE dwd.dwd_bixin_trade_sviporder_di_123 SET TBLPROPERTIES ('parquet.column.index.access'='true');或者set parquet.column.index.access = true可正常查询,希望可以配置默认该参数为true),目前内部环境该配置应该都没有默认true。
spark解决方式:
与hive类似
spark.sql.hive.convertMetastoreParquet=false
parquet.column.access.index=true
如果设置了 spark.sql.hive.convertMetastoreParquet=false,那就跟 Hive 行为相同;否则忽略这个参数 impala解决方式
目前集群查询parquet配置默认都是name
Demo-查询不一致(持续更新) - 图7

如需解决这种情况,需要手动在代码前set PARQUET_FALLBACK_SCHEMA_RESOLUTION = position 但该种情况如果是增删列,且不是最后一列,由于查询按position位置,会导致错位。

5.spark和impala查询不一致(函数原理不同)

spark正常
Demo-查询不一致(持续更新) - 图8
impala乱码
Demo-查询不一致(持续更新) - 图9
原因:

Demo-查询不一致(持续更新) - 图10

impala的substr切割得以3个字符为单位,每3个byte是一个中文字符【impala一个中文 3个字符单位】
Demo-查询不一致(持续更新) - 图11
这里和spark有区别。用户在查询时不会直接清楚怎么去规避这个问题。

6.spark和impala查询不一致(spark有隐式转换)

spark正常
Demo-查询不一致(持续更新) - 图12
impala无数据
Demo-查询不一致(持续更新) - 图13

原因:
这是由于datesub类的时间函数和本身过滤的分区条件例如ds的类型不同。我们需要cast成一样的类型。
Demo-查询不一致(持续更新) - 图14

例如datesub这种时间函数,返回的都是datetime类型的字段,这里表的分区字段ds的字段类型是string。在spark中可能会做隐式转换并去过滤数,在impala中不会这样。所以需要将datesub返回的dateatime强转为string。结果才能保持一致。很多类似的问题都是这个原因。

7.spark和impala查询不一致(实现方式不一样)

该函数用法:
Demo-查询不一致(持续更新) - 图15
impala正常:
Demo-查询不一致(持续更新) - 图16

spark获取为null
Demo-查询不一致(持续更新) - 图17

提取的url如下
Demo-查询不一致(持续更新) - 图18

原因:这是因为spark和impala内部实现逻辑不一样,Spark 是调用 java.net.URI。java方法判断url中带{}的是非法的url。所以这个函数分析不出对应的字段。而impala的函数底层逻辑是C++实现的。支持识别这种url。

结论:如果数据格式一定是这样,可以使用impala引擎,或者通过自己写udf的形式,使用spark实现。

8.spark离线开发查询没有数据,自助分析有数据(spark版本差异)

离线开发:
Demo-查询不一致(持续更新) - 图19
Demo-查询不一致(持续更新) - 图20

自助分析:
Demo-查询不一致(持续更新) - 图21

原因:spark3修改了日期类型的隐式转换规则,spark里的日期和字符串比较会转换成日期和日期比较,spark2里的日期和字符串比较会转换成字符串和字符串比较。
Demo-查询不一致(持续更新) - 图22

结论:如果是离线开发spark2运行,会直接比较字符串,那么直接比较后,数据可能会过滤不到,造成没有结果的问题。需要自行截断字符串处理。

9.spark自助分析可以运行,hive自助分析报错格式问题(sparksql于hive有语法差异)

Demo-查询不一致(持续更新) - 图23
如图,hive无法运行。自助分析spark可以运行。

原因:

Demo-查询不一致(持续更新) - 图24

sparksql和hive的语法不一样,hive不支持on子句中用or

10.Hive select有数据但是select count(*) 的结果不对

添加参数:set hive.compute.query.using.stats=false;

11.spark3写入数据,spark查询正常,hive引擎查询无数据

Demo-查询不一致(持续更新) - 图25
表分区字段为timestamp类型,hive string 转timestamp需强制转换,无法隐式转换。推荐用户修改表分区字段类型到string类型即可

12.spark3查询count(1)数据对不上

Demo-查询不一致(持续更新) - 图26
spark查询得到8w条数据
Demo-查询不一致(持续更新) - 图27
hive和impala查询出来有35w条数据

说明spark查询有出入,查看spark查询日志发现,实际读到的只有8w条数据
Demo-查询不一致(持续更新) - 图28
但是count(1)去重后有35w条数据,怀疑可能是有文件损坏
社区官网(https://spark.apache.org/docs/latest/configuration.html)

set spark.sql.files.ignoreCorruptFiles=false;

提供参数在本地进行查询显示了具体报错
Demo-查询不一致(持续更新) - 图29
具体原因:
由于升级到Spark 3.0+版本,读取Parquet INT96文件时可能会出现日期和时间戳转换的问题。具体来说,警告指出在读取日期早于1582年10月15日或时间戳早于1900年1月1日的数据时,由于Spark 3.0+使用了新的Proleptic Gregorian历法,与Spark 2.x或旧版Hive使用的历法不同,可能导致结果的差异性。

解决方法:
set spark.sql.parquet.int96RebaseModeInRead =LEGACY
增加参数后问题解决。


作者:刘思伟