spark sql 导出数据

如果用户希望在spark sql 中,执行某个sql 后,将其结果集保存到本地,并且指定csv 或者 json 格式,在 beeline 中,实现起来很麻烦。通常的做法是将其create table tempTable as *** ,通过将结果集写入到新的临时表中,进行保存,然后再通过其他方式export 到本地。

这种方式,对于 HDFS 是可行到,但是如果数据是保存在像SequoiaDB 中,就比较难办了。因为spark 向 SequoiaDB 写入记录时,可能部分task 会失败重试,这样就容易造成SequoiaDB 目标表中写入了重复记录,从而造成数据不准确的问题。

因此,需要寻找一种的新的方式,将其结果集准确地读取出来,并且写入本地文件。

在网上有很多替代方案,无外乎是通过beeline 或者 spark-sql ,执行 SQL 命令,通过重定向的方式,将结果集保存到指定文件中。

这样的方式,首先不讨论其输出格式的问题,最无法让人接受的是,spark-sql 需要将所有的结果数据收集到一个 Driver 进程中后,才会开始输出终端。这个过程有以下 3 个问题

  1. 时间久,如果数据量大了,Driver 收集的过程会很久,并且通过top 可以查看到进程CPU 飙升
  2. 容易OOM,当数据量增大后,因为需要将所有结果数据存储在内存中,一旦数据量用超了,就抛出 OOM 的错误,一切前功尽弃
  3. 输出格式,因为保存本地文件的内容就是输出终端的数据,CSV 格式不友好,有时候甚至会因为不可见字符而导致整个本地文件格式错乱,最终导致数据无法恢复

所以本文主要是向读者们介绍一种新的方式,直接使用 scala / python 语言开发的程序,利用 RDD 将其结果数据保存本地,输出格式支持 CSV 和 JSON。

  • scala 版本

scala 版本作者没有直接编写程序,但是通过 spark-shell 进行了验证

import org.apache.spark.sql.hive.HiveContext
// sc - existing spark context
val sqlContext = new HiveContext(sc)
val df = sqlContext.sql("SELECT * FROM test_sdb")
df.coalesce(1).write.format("com.databricks.spark.csv").mode("overwrite").option("header", "true").save("/opt/sequoiadb/chenfool")

如果有用户喜欢这个方式,可以考虑将程序打包成jar 包来执行。

导出格式的更多参数,请参考 python 版本

  • python 版本

在执行python 的脚本前,首先需要设置一下环境变量

export SPARK_HOME=/root/software/spark-2.1.1-bin-hadoop2.7
export PYTHONPATH=${SPARK_HOME}/python/:${SPARK_HOME}/python/lib/py4j-0.10.4-src.zip;

注意:py4j-0.10.4-src.zip 文件名可能随不同的spark 版本有所变化

然后准备以下脚本程序, spark_sql_export.py

import atexit
import os
import platform


import pyspark
from pyspark.context import SparkContext
from pyspark.sql import SparkSession, SQLContext

spark = SparkSession 
    .builder 
    .enableHiveSupport() 
    .getOrCreate()

df = spark.sql("SELECT * FROM test_sdb limit 100")

#df.coalesce(1).write.format("org.apache.spark.sql.json").mode("overwrite") 
#  .save("/opt/sequoiadb/chenfool")


df.coalesce(1).write.format("com.databricks.spark.csv").mode("overwrite") 
  .option("enforceSchema", "false") 
  .option("quoteAll", "true") 
  .option("escapeQuotes", "false") 
  .option("header", "true") 
  .option("delimiter", "|") 
  .option("charToEscapeQuoteEscaping", """) 
  .option("inferSchema", "true") 
  .option("ignoreLeadingWhiteSpace", "false") 
  .option("ignoreTrailingWhiteSpace", "false") 
  .save("/opt/sequoiadb/chenfool")

执行方式

python spark_sql_export.py

结果数据就会被保存在 /opt/sequoiadb/chenfool/part-00000* 文件中。

结果数据只会被保存在一个文件中,因为设置了 coalesce 参数。

JSON 格式请参考 spark_sql_export.py 注释部分。

CSV 的详细参数,可以参考spark 源码:${SPARK_HOME}/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/csv/CSVOptions.scala 

注意:

在spark 2.1.1 版本中,ignoreLeadingWhiteSpace 和 ignoreTrailingWhiteSpace 参数无法生效,默认值为:true。在 spark 2.4.0 版本中,经过测试,这两个参数才能够生效。如果要求保存的数据中不做 trim 操作,只能够将spark 升级为2.4.0 版本。

本博客参考了之前 spark 学习(二) 的内容,里面有介绍如果利用python 来执行spark 的程序的说明,感兴趣的读者们可以移步查阅

原文地址:https://www.cnblogs.com/chenfool/p/10808455.html