pyspark:为什么缓存这么慢

时间:2019-04-18 01:03:55

标签: apache-spark pyspark apache-spark-sql

我跑步时

import time
start_time = time.time()
print(df_join.count())
end_time = time.time()
print((end_time - start_time))

我得到

25721
19.099464416503906

我跑步时

start_time = time.time()
df_join.cache()
print(df_join.count())
end_time = time.time()
print((end_time - start_time))

5分钟后它仍在运行。缓存27行数据真的需要这么长时间吗?大约15到20列宽,复杂度是url字符串。

编辑1: 事实证明,我有一列,其类型是jsons数组。如果我将其取出,则一切正常。不幸的是,pyspark将其作为字符串读取,我不知道如何告诉它是jsons数组

我该如何改善?

2 个答案:

答案 0 :(得分:0)

不确定URL字符串的含义,但是字符串具有最大的字节数并在序列化时占用最多的内存...我会运行

df_join.explain()

并检查转换中触发了多少次重排...因为这是一个很小的数据集,所以减少到类似

spark.conf.set("spark.sql.shuffle.partitions, 8)

还希望确保每个执行器有足够的内核,可以在运行时通过启动shell进行设置,例如

pyspark --master yarn executor-cores 5

总体而言,速度缓慢可能是由诸如设置了什么部署(本地,独立,yarn [客户端/集群])配置参数的数据量之类的原因引起的...通常是我所见的原因是持久时间更长作业归结为由广泛的转换(联接/ aggs)触发的输出分区的数量,执行器内核不足(我相信启动时默认值为1),并且pyspark / sparkR的速度不快是因为JVM之外需要将串行对象与其他对象之间进行传输的独立进程

还要检查STORAGE TAB下的Spark UI,并确保所有分区都已100%缓存...如果仅一部分内存适合,那么您可能必须增加执行程序的内存,因为部分缓存的DF会导致大量检索问题未缓存的分区

pyspark --master yarn --executor-memory "gb"

很抱歉有很多建议... Spark有时是一个讨厌的小虫子,根本原因可能是一长串的问题

from pyspark.sql.functions import col, array

df = spark.createDataFrame([
    (["1, 2, 3"]),
    (["4, 5, 6"]),
    (["7, 8, 9"])
], ["string_array"])

df.select(array("string_array").alias("array_data")).printSchema()
df.select(array("string_array").alias("array_data")).show()

root
 |-- array_data: array (nullable = false)
 |    |-- element: string (containsNull = true)

+----------+
|array_data|
+----------+
| [1, 2, 3]|
| [4, 5, 6]|
| [7, 8, 9]|
+----------+

jsonDF = spark.range(1).selectExpr("""
  '{"myJSONValue" : [1, 2, 3]}' as jsonString""")
jsonDF.show(truncate=False)
jsonDF.printSchema()


jsonDF.select(array("jsonString").alias("json_array")).show(truncate=False)
jsonDF.select(array("jsonString").alias("json_array")).printSchema()


 +---------------------------+
    |jsonString                 |
    +---------------------------+
    |{"myJSONValue" : [1, 2, 3]}|
    +---------------------------+

root
 |-- jsonString: string (nullable = false)

+-----------------------------+
|json_array                   |
+-----------------------------+
|[{"myJSONValue" : [1, 2, 3]}]|
+-----------------------------+

root
 |-- json_array: array (nullable = false)
 |    |-- element: string (containsNull = false)

答案 1 :(得分:0)

一般来说,这里有多个因素:

  • count执行与SELECT COUNT(1) FROM table等效的查询-这使Spark可以进行大刀阔斧的早期优化,从而避免获取计算父表不需要的任何数据。

    但是,如果将数据标记为cached,缓存might take precedence,则必须提取计划中存在的所有列。

  • Spark SQL使用MEMORY_AND_DISK存储级别-分配和/或回收内存以及潜在的磁盘IO都很昂贵。

  • 最终缓存不是免费的午餐-它需要昂贵且广泛的转换-默认情况下hence _AND_DISK存储级别,以减少缓存逐出和重新计算的风险。

如果您假设最终数据仅包含少量行,则第一个组件是最有可能的罪魁祸首。