【问题标题】:Empty Spark dataset reading Hive table读取 Hive 表的空 Spark 数据集
【发布时间】:2022-01-02 23:02:45
【问题描述】:

使用相同的源和相同的逻辑创建了 2 个 Hive 表,但查询略有不同:

表1查询是:

create table test.table1 stored as orc as
    select
        f1,
        mc.f2 as f2,
        mc.f3 as f3,
        f4
    from src.test_table lateral view explode(multiple_field) mcTable as mc
    union all
    select
        f1,
        f5 as f2,
        f6 as f3,
        f4
    from src.test_table
    where multiple_field is null or size(multiple_field) < 1
;

接下来,表 2 查询 - 相同的逻辑,使用 outerexplode 缩短:

 create table test.table2 stored as orc as
     select
       f1,
       if(mc is null, f5, mc.f2) as f2,
       if(mc is null, f6, mc.f3) as f3,
       f4
 from src.test_table lateral view outer explode(multiple_field) mcTable as mc
;

两个表均已成功创建,包含相同的行数和相同的数据(由 Hive Beeline 客户端检查)。 然后我尝试用 Spark 读取表的数据:

SparkSession sparkSession = SparkSession
                .builder().config("hive.execution.engine","mr")
                .appName("OrcExportJob")
                .enableHiveSupport()
                .getOrCreate();

String hql = "select * from test.table1"; // or test.table2
Dataset<Row> sqlDF = sparkSession.sql(hql);

在 test.table2 的情况下没关系 - sqlDF 包含所有数据。 读取 test.table1 会导致不同的结果 - sqlDF 根本不包含任何数据(0 行)。 Spark 日志显示没有错误 - 就像表真的是空的一样。

我听说 Spark 在读取事务性或分区 Hive 表时遇到了一些问题 - 但事实并非如此。

四处挖掘,我发现 Hive 以不同的方式为我的表存储 ORC 文件:

/
├─ user/
│  ├─ hive/
│  │  ├─ warehouse/
│  │  │  ├─ test.db/
│  │  │  │  ├─ table1/
│  │  │  │  │  ├─ 1/
│  │  │  │  │  │  ├─ 1/
│  │  │  │  │  │  │  ├─ 000000_0
│  │  │  │  │  ├─ 2/
│  │  │  │  │  │  ├─ 000000_0
│  │  │  │  │  │  ├─ 000001_0
│  │  │  │  │  │  ├─ 000002_0
│  │  │  │  │  │  ├─ 000003_0
│  │  │  │  ├─ table2/
│  │  │  │  │  ├─ 000000_0
│  │  │  │  │  ├─ 000001_0
│  │  │  │  │  ├─ 000002_0
│  │  │  │  │  ├─ 000003_0

有人可以帮我找出 Spark 看不到表 1 数据的原因吗?

为什么 Hive 为表 1 保留 5 个目录结构复杂的文件,而表 2 只保留 4 个结构简单的文件?

它会以某种方式影响 Spark 读取过程吗?

附: Hive 版本是 2.3.3, Spark 版本是 2.4.4

【问题讨论】:

    标签: apache-spark hadoop hive


    【解决方案1】:

    通常数据文件位于没有子目录的表位置内。

    UNION ALL 正在被优化(很可能您正在使用 Tez)并且每个查询都并行运行,作为单独的映射器任务独立运行。这需要为 UNION ALL 中的每个查询创建单独的子目录,以便可以同时写入每个查询的结果,这就是您有两个目录的原因。

    这些设置允许 Hive 读取子目录:

    set hive.input.dir.recursive=true;
    set hive.mapred.supports.subdirectories=true;
    

    有一个问题 SPARK-26663 - Cannot query a Hive table with subdirectories - 因无法重现而关闭,因为他们执行了在 MR 而不是 Tez 上重现的步骤。

    如果您需要阅读此类表格,请尝试使用 HiveContext 并设置上述属性。

    顺便说一句,您的第二个查询效率更高,因为您只读取一次源表并且不创建子目录。

    您也可以尝试在 MR 上运行 CREATE TABLE,它不会创建子目录 (set hive.execution.engine=mr;)。

    还将 UNION ALL 包装到子查询中并添加诸如 DISTRIBUTE BY 或 ORDER 之类的内容将强制执行额外的 reduce 步骤,请参阅 https://stackoverflow.com/a/54998031/2700344

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-28
      • 2020-07-29
      • 1970-01-01
      • 2018-03-23
      • 2018-12-11
      • 2019-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多