【问题标题】:In Spark, is there a performance difference between querying DataFrames on CSV and JSON在 Spark 中,在 CSV 和 JSON 上查询 DataFrame 之间是否存在性能差异
【发布时间】:2016-02-04 05:24:25
【问题描述】:

我在 AWS S3 上有一个 CSV 文件和一个 JSON 文件(每个都有 500 万行/记录)。它们包含完全相同的数据,只是格式不同。

在具有 10 个任务节点的 EMR 集群上,我启动了 Spark(10 个执行器,40 个执行器核心)并创建了两个 DataFrame:一个针对 CSV,一个针对 JSON。

针对基于 JSON 文件构建的 DF 的查询的运行速度比针对基于 CSV 构建的 DF 的类似查询快 2-3 倍。我没有找到任何有关不同存储文件格式的性能差异的信息。

有人知道为什么对 JSON 上的 DF 的查询比 CSV 上的 DF 运行得更快吗?

下面的数据框创建代码

根据 JSON 文件创建 DF:

val hc_json = new org.apache.spark.sql.hive.HiveContext(sc)
val path_json = "s3://<mybucket>/<myjsonfile>.json"
val df_json = hc_json.read.json(path_json)
df_json.registerTempTable("table_json")
hc_json.sql("Select count(*) from table_json").collect()

根据 CSV 文件创建 DF:

(我在使用以下参数启动 Spark 时导入 spark-csv 包:--packages com.databricks:spark-csv_2.11:1.2.0)

val hc_csv = new org.apache.spark.sql.hive.HiveContext(sc)
val path_csv = "s3://<mybucket>/<mycsvfile>.csv"
val df_csv = hc_csv.load("com.databricks.spark.csv", Map("path" -> path,"header"->"false"))
df_csv.registerTempTable("table_csv")
hc_csv.sql("Select count(*) from table_csv").collect()

【问题讨论】:

    标签: amazon-web-services amazon-s3 apache-spark apache-spark-sql


    【解决方案1】:

    使用不同数据源创建的 DataFrame 之间应该没有性能差异,它包括 JSON 或 csv。

    问题是当您在上面的 sn-ps 中调用 hc_json.sql 时,您不仅会执行查询,还会在每次执行查询时从磁盘加载数据。这意味着您测量的不是查询时间,而是磁盘访问+解析+查询。对于 JSON 和 csv,第一个 * 和最后一个应该或多或少相同,但解析会因源而异。

    如果您只想测量实际查询时间,则应缓存数据并执行操作以确保数据已实际加载。例如

    df_csv.registerTempTable("table_csv")
    sqlContext.cacheTable("table_csv")
    hc_csv.sql("SELECT count(*) FROM table_csv").collect()
    

    现在应该加载数据,您可以预期类似的查询时间。

    编辑这里实际上还有一个不同之处。从 JSON 源创建的 DataFrame 将获得正确的数据类型,而来自 csv 的数据帧,不提供架构或设置 inferSchema 选项将所有内容读取为字符串。


    * 正如kostya 指出的那样,JSON 文件通常更小。另一方面,JSON 与 csv 不同,可以很好地处理稀疏日期。

    【讨论】:

    • 感谢您的回复 - 我忘了缓存。我知道我可以缓存 DataFrame,但我认为最好在注册后缓存表。不过,我不确定这有什么不同。
    • 如果您想使用cacheTable,这是首选方法,那么您必须先注册。
    【解决方案2】:

    许多因素都会影响查询性能,包括:

    • 数据格式
    • DataFrame的DataSource的实现细节
    • 查询本身
    • 数据结构

    对于大多数查询而言,使用 CSV 很可能会更快,因为文件大小小于 JSON,并且需要从磁盘读取的数据更少。使用 parquet 文件格式可能会更快,因为文件更小,解码时间更快。

    像 (select count(*) from table_csv) 这样的查询对于某些格式(例如 parquet)可以运行得更快,因为 Spark 足够聪明,可以在没有请求列的情况下跳过读取数据。

    @zero323 建议先将数据加载到内存中,这很可能会提高查询执行速度,但如果您的集群中没有足够的 RAM 来容纳整个数据集,它将无法工作。

    【讨论】:

    • 关于我的文件大小,JSON (2.1GB) 实际上比我的 CSV (2.6GB) 小。它们具有完全相同的数据,只是格式不同。我的 JSON 每行只有一条记录,因此它可以通过“hc_json.read.json(path_json)”正确导入。当您说“如果没有请求列,足够聪明以跳过解析”时,我能问一下您的意思吗?你的意思是在查询时?
    • 令人惊讶的是你的JSON文件更小,可能数据不一样。 JSON 格式为每一行重复字段名称,而 CSV 仅包含一次作为第一行。执行查询时会解析文件(如果未缓存表)。
    • 如果没有请求列,DataSource 足够聪明,可以跳过解析 - 你错了。 count(*) 在查询命中源之前在不可为空的情况下由优化器转换为 count(1)
    • 关于 csv 与 JSON 的大小并不是一切。两者都不是很智能的格式,但与 csv 不同的是,JSON 是标准化的,可以高效解析。
    • @zero323,我认为你是对的,我错了,尽管理论上这是可能的;)关于第二点,没有理由说明高效的 CSV 解析器会比 JSON 解析器慢。跨度>
    猜你喜欢
    • 1970-01-01
    • 2021-04-29
    • 2012-03-05
    • 2014-05-17
    • 1970-01-01
    • 2014-02-23
    • 2010-10-02
    • 2012-08-21
    • 2019-06-15
    相关资源
    最近更新 更多