Pyspark没有记录到文件

Posted

技术标签:

【中文标题】Pyspark没有记录到文件【英文标题】:Pyspark not logging to file 【发布时间】:2019-01-17 11:45:15 【问题描述】:

我正在使用命令 spark-submit 启动一个 pyspark 脚本,将标准输出重定向到文件也使用 tee 来生成日志。

命令如下:

spark-submit test.py  | tee test.xxx

问题是只有用户定义函数UDF内的print只打印在终端上而不是文件tee test.xxx,而所有其他打印都将写入终端和文件。

为了模拟这种行为,我创建了这个最小的完整工作示例:

from pyspark import SparkContext
import pyspark.sql.functions as F #udf, col, count, sum, when, avg, mean, min
from pyspark.sql import SQLContext
from pyspark.sql.types import *
def cutURL(input):
    cutURL.lineNumber += 1
    if input==None or input=="" or not(isinstance(input, str)):
        print("WARNING: not proper string URL: empty or null. Possible line: " + str(cutURL.lineNumber))
        res = "Unknown"
        if input==None: print("string is none")
        elif not(isinstance(input, str)): print("input not a string")
        elif input=="": print("empty string")
        return res
    res = input
    try:
        if (bool(re.search("/devices(.+?)&maxdist=[0-9]+", input))):
            res = re.search("/devices(.+?)&maxdist=[0-9]+", input).group()
        else:
            res = re.sub(r'.*?(/devices/[^/]*_)[^/_]*(/read)', r'\1\2', input)
    except:
        print("WARning in cutURL:")
        print(" not matching regular expression: is the string")
    return res


sc = SparkContext.getOrCreate()
sc.setLogLevel("WARN")
sqlContext = SQLContext(sc)
cutURL.lineNumber = 0
print("This will be printed to both file and terminal")
df = sqlContext.createDataFrame([None, "example",  "others"], "string").toDF("url")
cut_URL_udf =  F.udf(cutURL, StringType())
df2 = df.select(cut_URL_udf("url").alias("cut_URL"))
df2.show()

在这种情况下,字符串WARNING: not proper string URL: empty or null. Possible line: 仅打印在终端上,而不打印到文件中。

如何使 pyspark UDF 中生成的输出也重定向到文件?

编辑 为了更好地解释我的问题,我添加了print("This will be printed to both file and terminal") 行。这将打印到终端并记录到文件,而 udf 中的 print 仅到终端。

【问题讨论】:

我认为问题在于 pyspark 可能更改了您的标准输出,因此当您“打印”时它不会直接进入标准输出,从而绕过 tee。您可能需要手动控制输出句柄或使用日志记录模块来避免重新发明*** 但是为什么它只改变 udf 内的打印? 不幸的是,我对 pyspark 不熟悉,所以我无法肯定地回答这个问题,但它可能会打开自己的进程并根据自己的内部逻辑处理输出,这是一种相当普遍的行为跨度> 【参考方案1】:

编辑:抱歉误读了已经重定向的内容

解决方案是使用正确的日志记录而不是打印:

查找 python 日志记录:

https://docs.python.org/3/library/logging.html https://docs.python.org/3/howto/logging-cookbook.html

登录到控制台和文件的示例:

import logging

# set up logging to file - see previous section for more details
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
                    datefmt='%m-%d %H:%M',
                    filename='/temp/myapp.log',
                    filemode='w')
# define a Handler which writes INFO messages or higher to the sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.INFO)
# set a format which is simpler for console use
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
# tell the handler to use this format
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)

# Now, we can log to the root logger, or any other logger. First the root...
logging.info('Jackdaws love my big sphinx of quartz.')

【讨论】:

我不是用 tee 重定向到文件吗?在我的原始程序中,除了 udf 中的这一部分之外,所有内容都被打印到文件和终端中

以上是关于Pyspark没有记录到文件的主要内容,如果未能解决你的问题,请参考以下文章

PySpark (Python):通过 SparkContext.newAPIHadoopFile 加载多行记录

PySpark - 分区中覆盖的数据

从 Pyspark 在 HDFS 中保存文件

Pyspark 根据数据框 groupBy 制作多个文件

将重复记录合并到 pyspark 数据框中的单个记录中

如何从数据框中获取 1000 条记录并使用 PySpark 写入文件?