读取 Hive 的空 Spark 数据集 table
Empty Spark dataset reading Hive table
有 2 个 Hive table 使用相同的来源和相同的逻辑创建,但查询略有不同:
Table 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
;
接下来,table 2 查询 - 相同的逻辑,使用 outer explode 缩短:
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
;
两个 table 都已成功创建,包含相同的行数和相同的数据(由 Hive Beeline 客户端检查)。
然后我尝试用 Spark 读取 table 的数据:
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);
在测试的情况下。table2 没关系 - sqlDF 包含所有数据。
读取 test.table1 会导致不同的结果 - sqlDF 根本不包含任何数据(0 行)。
Spark 日志显示没有错误 - 就像 table 真的是空的。
我听说 Spark 在读取事务性或分区 Hive tables 时遇到一些问题 - 但事实并非如此。
四处挖掘,我发现 Hive 以不同的方式为我的 table 存储 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 看不到 Table 1 个数据的原因?
为什么 Hive 为 Table1 保留 5 个目录结构复杂的文件,为 Table2 保留 4 个结构简单的文件?
它会以某种方式影响 Spark 读取过程吗?
P.S。蜂巢版本为 2.3.3,
Spark 版本为 2.4.4
通常数据文件位于 table 没有子目录的位置。
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 上重现的步骤。
如果您需要阅读此类 table,请尝试使用 HiveContext 并设置上述属性。
顺便说一下,您的第二个查询效率更高,因为您只读取一次源 table 并且不创建子目录。
你也可以试试 运行 你在 MR 上创建 TABLE,它不会创建子目录 (set hive.execution.engine=mr;
)。
还将 UNION ALL 包装到子查询中并添加诸如 DISTRIBUTE BY 或 ORDER 之类的内容将强制执行额外的减少步骤,请参阅
有 2 个 Hive table 使用相同的来源和相同的逻辑创建,但查询略有不同:
Table 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
;
接下来,table 2 查询 - 相同的逻辑,使用 outer explode 缩短:
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
;
两个 table 都已成功创建,包含相同的行数和相同的数据(由 Hive Beeline 客户端检查)。 然后我尝试用 Spark 读取 table 的数据:
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);
在测试的情况下。table2 没关系 - sqlDF 包含所有数据。 读取 test.table1 会导致不同的结果 - sqlDF 根本不包含任何数据(0 行)。 Spark 日志显示没有错误 - 就像 table 真的是空的。
我听说 Spark 在读取事务性或分区 Hive tables 时遇到一些问题 - 但事实并非如此。
四处挖掘,我发现 Hive 以不同的方式为我的 table 存储 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 看不到 Table 1 个数据的原因?
为什么 Hive 为 Table1 保留 5 个目录结构复杂的文件,为 Table2 保留 4 个结构简单的文件?
它会以某种方式影响 Spark 读取过程吗?
P.S。蜂巢版本为 2.3.3, Spark 版本为 2.4.4
通常数据文件位于 table 没有子目录的位置。
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 上重现的步骤。
如果您需要阅读此类 table,请尝试使用 HiveContext 并设置上述属性。
顺便说一下,您的第二个查询效率更高,因为您只读取一次源 table 并且不创建子目录。
你也可以试试 运行 你在 MR 上创建 TABLE,它不会创建子目录 (set hive.execution.engine=mr;
)。
还将 UNION ALL 包装到子查询中并添加诸如 DISTRIBUTE BY 或 ORDER 之类的内容将强制执行额外的减少步骤,请参阅