如何从 HDFS 中的数据创建 EXTERNAL Spark 表

Gab*_*eda 5 hive apache-spark

我已将 HDFS 中的镶木地板表加载到 DataFrame 中:

val df = spark.read.parquet("hdfs://user/zeppelin/my_table")

我现在想要将此表公开给 Spark SQL,但这必须是一个永久表,因为我想从 JDBC 连接或其他 Spark 会话访问它。

快速的方法可能是调用df.write.saveAsTable方法,但在这种情况下,它将具体化 DataFrame 的内容并创建指向 Hive 元存储中的数据的指针,从而在 HDFS 中创建数据的另一个副本。

我不想拥有相同数据的两个副本,因此我希望创建一个外部表来指向现有数据。

Gab*_*eda 3

要创建 Spark 外部表,您必须指定 DataFrameWriter 的“path”选项。像这样的东西:

df.write.
  option("path","hdfs://user/zeppelin/my_mytable").
  saveAsTable("my_table")
Run Code Online (Sandbox Code Playgroud)

但问题是,它会清空你的 hdfs 路径,hdfs://user/zeppelin/my_mytable消除你现有的文件,并会导致org.apache.spark.SparkException: Job aborted.. 这看起来像是 Spark API 中的一个错误......

不管怎样,解决方法(在 Spark 2.3 中测试)是从 Spark DDL 创建一个外部表。如果您的表有很多列,那么创建 DDL 可能会很麻烦。幸运的是,从 Spark 2.0 开始,您可以调用 DDLSHOW CREATE TABLE让 Spark 来完成繁重的工作。问题是您实际上可以SHOW CREATE TABLE在持久表中运行。

如果表很大,我建议获取表的样本,将其保存到另一个位置,然后获取 DDL。像这样的东西:

// Create a sample of the table 
val df = spark.read.parquet("hdfs://user/zeppelin/my_table")
df.limit(1).write.
    option("path", "/user/zeppelin/my_table_tmp").
    saveAsTable("my_table_tmp")

// Now get the DDL, do not truncate output
spark.sql("SHOW CREATE TABLE my_table_tmp").show(1, false)
Run Code Online (Sandbox Code Playgroud)

您将得到如下 DDL:

CREATE TABLE `my_table_tmp` (`ID` INT, `Descr` STRING)
USING parquet
OPTIONS (
  `serialization.format` '1',
  path 'hdfs:///user/zeppelin/my_table_tmp')
Run Code Online (Sandbox Code Playgroud)

您希望将其更改为具有表的原始名称原始数据的路径。您现在可以运行以下命令来创建指向现有 HDFS 数据的 Spark 外部表:

spark.sql("""
  CREATE TABLE `my_table` (`ID` INT, `Descr` STRING)
  USING parquet
  OPTIONS (
    `serialization.format` '1',
    path 'hdfs:///user/zeppelin/my_table')""")
Run Code Online (Sandbox Code Playgroud)