- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前正在使用 PySpark 开发我的第一个完整系统,我遇到了一些奇怪的、与内存相关的问题。在其中一个阶段,我想类似于 Split-Apply-Combine 策略以修改 DataFrame。也就是说,我想对给定列定义的每个组应用一个函数,最后将它们全部组合起来。问题是,我要应用的函数是一种适用于“说” Pandas 惯用语的拟合模型的预测方法,即它被矢量化并以 Pandas 系列作为输入。
然后我设计了一个迭代策略,遍历组并手动应用 pandas_udf.Scalar 来解决问题。组合部分是使用对 DataFrame.unionByName() 的增量调用完成的。我决定不使用 GroupedMap 类型的 pandas_udf 因为文档声明内存应该由用户管理,并且当其中一个组可能太大而无法将其保存在内存中或由一个表示时,您应该特别小心 Pandas 数据框。
主要问题是所有处理似乎都运行良好,但最后我想将最终的 DataFrame 序列化为 Parquet 文件。正是在这一点上,我收到了很多关于 DataFrameWriter 的类似 Java 的错误,或者内存不足的异常。
我已经在 Windows 和 Linux 机器上尝试过代码。我设法避免错误的唯一方法是增加机器中的 --driver-memory 值。每个平台的最小值都不同,并且取决于问题的大小,这让我怀疑内存泄漏。
问题直到我开始使用pandas_udf 才出现。我认为在使用 pandas_udf 时,在整个 pyarrow 序列化过程中的某处可能存在内存泄漏。
我创建了一个最小的可重现示例。如果我直接使用 Python 运行这个脚本,它会产生错误。使用 spark-submit 并增加很多驱动程序内存,可以使其工作。
import pyspark
import pyspark.sql.functions as F
import pyspark.sql.types as spktyp
# Dummy pandas_udf -------------------------------------------------------------
@F.pandas_udf(spktyp.DoubleType())
def predict(x):
return x + 100.0
# Initialization ---------------------------------------------------------------
spark = pyspark.sql.SparkSession.builder.appName(
"mre").master("local[3]").getOrCreate()
sc = spark.sparkContext
# Generate a dataframe ---------------------------------------------------------
out_path = "out.parquet"
z = 105
m = 750000
schema = spktyp.StructType(
[spktyp.StructField("ID", spktyp.DoubleType(), True)]
)
df = spark.createDataFrame(
[(float(i),) for i in range(m)],
schema
)
for j in range(z):
df = df.withColumn(
f"N{j}",
F.col("ID") + float(j)
)
df = df.withColumn(
"X",
F.array(
F.lit("A"),
F.lit("B"),
F.lit("C"),
F.lit("D"),
F.lit("E")
).getItem(
(F.rand()*3).cast("int")
)
)
# Set the column names for grouping, input and output --------------------------
group_col = "X"
in_col = "N0"
out_col = "EP"
# Extract different group ids in grouping variable -----------------------------
rows = df.select(group_col).distinct().collect()
groups = [row[group_col] for row in rows]
print(f"Groups: {groups}")
# Split and treat the first id -------------------------------------------------
first, *others = groups
cur_df = df.filter(F.col(group_col) == first)
result = cur_df.withColumn(
out_col,
predict(in_col)
)
# Traverse the remaining group ids ---------------------------------------------
for i, other in enumerate(others):
cur_df = df.filter(F.col(group_col) == other)
new_df = cur_df.withColumn(
out_col,
predict(in_col)
)
# Incremental union --------------------------------------------------------
result = result.unionByName(new_df)
# Save to disk -----------------------------------------------------------------
result.write.mode("overwrite").parquet(out_path)
令人震惊的是(至少对我而言),如果我在序列化语句之前调用 repartition(),问题似乎就消失了。
result = result.repartition(result.rdd.getNumPartitions())
result.write.mode("overwrite").parquet(out_path)
将这条线放到位后,我可以降低很多驱动程序内存配置,并且脚本运行良好。我几乎无法理解所有这些因素之间的关系,尽管我怀疑代码的惰性评估和 pyarrow 序列化可能是相关的。
这是我用于开发的当前环境:
arrow-cpp 0.13.0 py36hee3af98_1 conda-forge
asn1crypto 0.24.0 py36_1003 conda-forge
astroid 2.2.5 py36_0
atomicwrites 1.3.0 py_0 conda-forge
attrs 19.1.0 py_0 conda-forge
blas 1.0 mkl
boost-cpp 1.68.0 h6a4c333_1000 conda-forge
brotli 1.0.7 he025d50_1000 conda-forge
ca-certificates 2019.3.9 hecc5488_0 conda-forge
certifi 2019.3.9 py36_0 conda-forge
cffi 1.12.3 py36hb32ad35_0 conda-forge
chardet 3.0.4 py36_1003 conda-forge
colorama 0.4.1 py36_0
cryptography 2.6.1 py36hb32ad35_0 conda-forge
dill 0.2.9 py36_0
docopt 0.6.2 py36_0
entrypoints 0.3 py36_0
falcon 1.4.1.post1 py36hfa6e2cd_1000 conda-forge
fastavro 0.21.21 py36hfa6e2cd_0 conda-forge
flake8 3.7.7 py36_0
future 0.17.1 py36_1000 conda-forge
gflags 2.2.2 ha925a31_0
glog 0.3.5 h6538335_1
hug 2.5.2 py36hfa6e2cd_0 conda-forge
icc_rt 2019.0.0 h0cc432a_1
idna 2.8 py36_1000 conda-forge
intel-openmp 2019.3 203
isort 4.3.17 py36_0
lazy-object-proxy 1.3.1 py36hfa6e2cd_2
libboost 1.67.0 hd9e427e_4
libprotobuf 3.7.1 h1a1b453_0 conda-forge
lz4-c 1.8.1.2 h2fa13f4_0
mccabe 0.6.1 py36_1
mkl 2018.0.3 1
mkl_fft 1.0.6 py36hdbbee80_0
mkl_random 1.0.1 py36h77b88f5_1
more-itertools 4.3.0 py36_1000 conda-forge
ninabrlong 0.1.0 dev_0 <develop>
nose 1.3.7 py36_1002 conda-forge
nose-exclude 0.5.0 py_0 conda-forge
numpy 1.15.0 py36h9fa60d3_0
numpy-base 1.15.0 py36h4a99626_0
openssl 1.1.1b hfa6e2cd_2 conda-forge
pandas 0.23.3 py36h830ac7b_0
parquet-cpp 1.5.1 2 conda-forge
pip 19.0.3 py36_0
pluggy 0.11.0 py_0 conda-forge
progressbar2 3.38.0 py_1 conda-forge
py 1.8.0 py_0 conda-forge
py4j 0.10.7 py36_0
pyarrow 0.13.0 py36h8c67754_0 conda-forge
pycodestyle 2.5.0 py36_0
pycparser 2.19 py36_1 conda-forge
pyflakes 2.1.1 py36_0
pygam 0.8.0 py_0 conda-forge
pylint 2.3.1 py36_0
pyopenssl 19.0.0 py36_0 conda-forge
pyreadline 2.1 py36_1
pysocks 1.6.8 py36_1002 conda-forge
pyspark 2.4.1 py_0
pytest 4.5.0 py36_0 conda-forge
pytest-runner 4.4 py_0 conda-forge
python 3.6.6 hea74fb7_0
python-dateutil 2.8.0 py36_0
python-hdfs 2.3.1 py_0 conda-forge
python-mimeparse 1.6.0 py_1 conda-forge
python-utils 2.3.0 py_1 conda-forge
pytz 2019.1 py_0
re2 2019.04.01 vc14h6538335_0 [vc14] conda-forge
requests 2.21.0 py36_1000 conda-forge
requests-kerberos 0.12.0 py36_0
scikit-learn 0.20.1 py36hb854c30_0
scipy 1.1.0 py36hc28095f_0
setuptools 41.0.0 py36_0
six 1.12.0 py36_0
snappy 1.1.7 h777316e_3
sqlite 3.28.0 he774522_0
thrift-cpp 0.12.0 h59828bf_1002 conda-forge
typed-ast 1.3.1 py36he774522_0
urllib3 1.24.2 py36_0 conda-forge
vc 14.1 h0510ff6_4
vs2015_runtime 14.15.26706 h3a45250_0
wcwidth 0.1.7 py_1 conda-forge
wheel 0.33.1 py36_0
win_inet_pton 1.1.0 py36_0 conda-forge
wincertstore 0.2 py36h7fe50ca_0
winkerberos 0.7.0 py36_1
wrapt 1.11.1 py36he774522_0
xz 5.2.4 h2fa13f4_4
zlib 1.2.11 h62dcd97_3
zstd 1.3.3 hfe6a214_0
任何提示或帮助将不胜感激。
最佳答案
我想对你的帖子发表评论,但我的声誉太低了。
根据我的经验,udf 会大大降低你的性能,特别是如果你用 python(或 pandas?)编写它们。有一篇文章,为什么你不应该使用 python udfs 而是使用 scala udfs:https://medium.com/wbaa/using-scala-udfs-in-pyspark-b70033dd69b9
在我的案例中,可以使用内置函数,即使它非常复杂,运行时间也比以前减少了大约 5%。
对于您的 OOM 错误以及为什么重新分区对您有效,我没有任何解释。我能给你的唯一建议是尽可能避免使用 UDF,尽管在你的情况下这似乎并不那么容易。
关于python - 使用 pandas_udf 和 Parquet 序列化时内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56329093/
我在使用以下代码时遇到 pandas_udf 错误。代码是基于另一列创建具有数据类型的列。相同的代码适用于正常较慢的 udf(已注释掉)。 基本上任何更复杂的“字符串”+数据都会返回错误。 # fro
我面临着繁重的数据转换。简而言之,我有数据列,每个数据列都包含与一些序数相对应的字符串。例如,高、中和低。我的目标是将这些字符串映射到整数以保留顺序。在本例中,为LOW -> 0、MID -> 1 和
我正在尝试制作一个 pandas UDF,它接受两列整数值,并根据这些值之间的差异返回一个小数数组,其长度等于上述差异。 到目前为止,这是我的尝试,我一直在尝试各种不同的方法来让它发挥作用,但这是总体
我正在附加到 AWS EMR 实例的 jupyter notebook 上尝试一些与 pyspark 相关的实验。我有一个 spark 数据框,它从 s3 读取数据,然后过滤掉一些东西。使用 df1.
我开始在本地玩 Spark 并发现这个奇怪的问题 1) pip install pyspark==2.3.1 2)pyspark> 将 Pandas 导入为 pd 从 pyspark.sql.func
This answer很好地解释了如何使用 pyspark 的 groupby 和 pandas_udf 进行自定义聚合。但是,我不可能像示例的这一部分所示那样手动声明我的架构 from pyspar
我正在使用 pandas_udf 在我的 Spark 集群上应用机器学习模型,并且有兴趣预定义通过箭头发送到 UDF 的最小记录数。 我遵循了大部分 UDF 的 databricks 教程... ht
我创建了一个 Pandas UDF,它将输入一个数据帧,在 Primary_Key 和 Predictions 上预测并输出一个数据帧。 schema = StructType([StructFiel
我写了一个UDF。它非常慢。我想用 pandas_udf 替换它以利用矢量化。 实际的 udf 有点复杂,但我创建了一个简化的玩具版本。 我的问题:是否可以将玩具示例中的 UDF 替换为可以利用矢量化
我已经测试过 logger和 print无法在 pandas_udf 中打印消息,无论是集群模式还是客户端模式。 测试代码: import sys import numpy as np import
我有这个 df: df = spark.createDataFrame( [('row_a', 5.0, 0.0, 11.0), ('row_b', 3394.0, 0.0, 454
我在 Jupyter 笔记本中运行以下代码,但出现 ImportError。请注意,“udf”可以导入到 Jupyter 中。 从 pyspark.sql.functions 导入 pandas_ud
我有这个 df: df = spark.createDataFrame( [('row_a', 5.0, 0.0, 11.0), ('row_b', 3394.0, 0.0, 454
可以使用外部库,例如 textdistance在pandas_udf里面?我已经尝试过,但收到此错误: ValueError: The truth value of a Series is ambig
我目前正在使用 PySpark 开发我的第一个完整系统,我遇到了一些奇怪的、与内存相关的问题。在其中一个阶段,我想类似于 Split-Apply-Combine 策略以修改 DataFrame。也就是
我正在使用 PySpark 的新 pandas_udf 装饰器,我试图让它将多个列作为输入并返回一个系列作为输入,但是,我收到一个 TypeError : 无效参数 示例代码 @pandas_udf(
我正在使用 PySpark 的新 pandas_udf 装饰器,我试图让它将多个列作为输入并返回一个系列作为输入,但是,我收到一个 TypeError : 无效参数 示例代码 @pandas_udf(
我无法从可用的 Pyspark 文档中复制 Spark 代码 here. 例如,当我尝试以下与 Grouped Map 有关的代码时: import numpy as np import pandas
我正在尝试将函数应用于 pyspark 中的每个数据集组。我遇到的第一个错误是 Py4JError: An error occurred while calling o62.__getnewargs_
我正在构建多个 Prophet 模型,其中每个模型都传递给 pandas_udf 函数,该函数训练模型并使用 MLflow 存储结果。 @pandas_udf(result_schema, Panda
我是一名优秀的程序员,十分优秀!