个性化阅读
专注于IT技术分析

Python中的Apache Spark:新手指南

本文概述

你可能已经知道Apache Spark作为用于大数据处理的快速通用引擎, 具有用于流传输, SQL, 机器学习和图形处理的内置模块。它以其速度, 易用性, 通用性以及几乎可以在任何地方运行的能力而闻名。尽管Spark是数据工程师最需要的工具之一, 但数据科学家在进行探索性数据分析, 特征提取, 监督学习和模型评估时也可以从Spark中受益。

今天的帖子将根据9个最常见的问题向你介绍一些Python中的基本Spark主题, 例如

  • 使用Spark时应该选择哪种语言:Python或Scala?与另一种相比, 使用一种有什么好处?
  • 接下来, 你将看到如何在Python中使用Spark:本地或通过Jupyter Notebook。你将学习如何通过Jupyter笔记本添加Spark, 通过使用内核或通过Docker容器在Jupyter中运行PySpark, 来学习如何安装Jupyter笔记本以及使用Jupyter笔记本运行Spark应用程序。
  • 既然你已经确定可以在Python中使用Spark, 那么你将了解使用PySpark时经常使用的基本构建模块之一:RDD。你将了解RDD与DataFrame API和DataSet API的区别以及何时使用哪种结构。
  • 然后, 你将详细了解Spark DataFrame和Pandas DataFrame之间的区别, 以及如何从一个切换到另一个。如果你想进一步了解Pandas DataFrames, 请考虑srcmini的Pandas Foundations课程。
  • 使用RDD时, 了解RDD动作和转换之间的区别非常重要,
  • 以及为什么需要缓存或保留RDD, 或者何时需要广播变量。
  • 最后, 你将了解Spark中的一些最佳做法, 例如使用DataFrames和Spark UI,
  • 你还将看到如何关闭PySpark的日志记录。

Spark:Python还是Scala?

一开始, 你可能会读到很多关于将Spark与Python或Scala结合使用的信息。在论坛上对此进行了一些讨论。

Spark性能:Scala还是Python?

总的来说, 大多数开发人员似乎都同意Scala在性能和并发方面胜出:当你使用Spark时, 它肯定比Python快, 并且当你谈论并发时, 可以肯定Scala和Play框架可以做到这一点易于编写易于推理的干净且高性能的异步代码。播放是完全异步的, 这使得无需处理线程即可拥有许多并发连接。在并行中进行I / O调用会更容易, 以提高性能并启用实时, 流式传输和服务器推送技术。

请注意, 在调用远程服务时, 异步代码允许非阻塞I / O。让我们用一个示例来不同地说明它:当你有两行代码, 其中第一行查询数据库, 而下一行将内容打印到控制台时, 同步编程将等待查询完成, 然后再打印内容。你的程序(暂时)被阻止。如果你的编程语言不支持异步编程, 则需要创建线程以并行执行代码行。另一方面, 在查询数据库时, 异步编程将已打印到控制台。查询将在后台处理。

简而言之, 以上内容解释了为什么即使在Spark中进行结构化流式传输似乎已经缩小了差距时, 仍强烈建议在处理流式数据时仍建议在Python上使用Scala。

但是, 流数据并不是你可能要考虑的唯一性能问题。

当你使用DataFrame API时, Python和Scala之间并没有太大的区别, 但是你需要警惕用户定义函数(UDF), 该函数的效率不如Scala等效。因此, 如果你使用Python, 则应该偏爱内置表达式。使用Python时, 也请确保不要不必要地在DataFrame和RDD之间传递数据, 因为数据传输的序列化和反序列化特别昂贵。

请记住, 序列化是将对象转换为字节序列的过程, 这些字节序列可以保留到磁盘或数据库中, 也可以通过流发送。从字节序列创建对象的反向过程称为反序列化。在一个更实际的示例中, 你可以拥有一个电影应用程序, 例如, 带有服务器和客户端。每当来自客户端的应用程序向服务器发送查询以检索(例如)电影列表时。服务器需要将可用的Movie对象的列表传递回客户端, 该对象需要序列化。

学习Spark:Python还是Scala?

就学习曲线和易于使用而言, Python似乎是一个更好的选择, 因为它比Scala更加冗长且易读。对于那些没有太多编程经验的人来说是理想的选择。

但是, 即使对于那些具有一定编程经验的人来说, 使用Python使用Spark也不是一件容易的事, 正如你在以下段落中所看到的。

火花和类型安全:Scala还是Python?

在某种程度上介于中间的两件事是类型安全和使用Python或Scala时获得的高级功能的数量。对于类型安全方面的问题, 你可以说Python在进行小型临时实验时是一个不错的选择, 而Scala在处理大型生产项目时则是很好的选择。这主要是因为重构时, 像Scala这样的静态类型语言要容易得多, 而且没有麻烦。

记住, 当一种语言是静态类型时, 每个变量名都被绑定到一个类型和一个对象上。类型检查发生在编译时。典型示例是Java或Scala。请注意, 在Scala的情况下, 类型系统可以推断出变量的类型, 因此有一种类型推断的形式可以使你的工作更快一些。当然, 在动态类型语言中, 每个变量名都仅绑定到一个对象, 除非它为null。类型检查在运行时发生。作为开发人员, 这通常意味着你可以更快地工作, 因为你不必每次都指定类型。这里的典型示例是Python或Ruby。

让我们看得见。考虑以下Java和Python代码块:


# Java
String str = "Hello"; 
str = 5;             

# Python
str = "Hello" 
str = 5      

在Java中将整数5分配给str会产生错误, 因为你将其声明为String。在Python中, 这不会有问题。

请注意, Spark DataSet是静态类型的, 在Python中并没有真正的位置。稍后, 你将详细了解此内容。

Spark和高级功能:Python还是Scala?

最后, 有些高级功能可能会影响你使用Python或Scala。在这里, 你不得不争论说, 如果你在谈论数据科学, 则Python具有主要优势, 因为它为用户提供了许多用于机器学习和自然语言处理的出色工具, 例如SparkMLib。

总结

简而言之, 使用Spark时, 两种语言都有其优点和缺点。是否选择一个取决于你的项目需求, 你自己或你的团队的能力, …给出的一般建议是使用Scala, 除非你已经精通它或者没有太多的编程经验。 。这意味着, 最后, 重要的是, 你必须知道如何使用两者!

PS。如果你想开始使用PySpark, 请不要错过srcmini的PySpark备忘单。

如何安装Spark

安装Spark并使用它可能是一项艰巨的任务。本节将更深入地介绍如何安装它以及开始使用它的选择。

首先, 检查是否已安装Java jdk。然后, 转到Spark下载页面。在前三个步骤中保留默认选项, 然后在步骤4中找到可下载的链接。单击以下载它。

接下来, 请确保解压缩显示在”下载”文件夹中的目录。接下来, 将未压缩的文件夹移动到/ usr / local / spark。


$ mv spark-2.1.0-bin-hadoop2.7 /usr/local/spark 

现在你已经准备就绪, 请在/ usr / local / spark中打开README文件。如果你拥有尚未构建的版本, 将会看到需要运行一个命令来构建Spark。因此, 请确保你运行以下命令:


$ build/mvn -DskipTests clean package run

这可能需要一段时间, 但是之后, 你就可以准备就绪!

互动式Spark Shell

接下来, 你可以通过在上一节结尾处所在的同一文件夹中键入./bin/pyspark, 立即开始在Spark shell中工作。这可能需要一些时间, 但是最终, 你会看到类似以下的内容:


Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_, _/_/ /_/\_\   version 2.1.0
      /_/

Using Python version 2.7.13 (v2.7.13:a06454b1afa1, Dec 17 2016 12:39:47)
SparkSession available as 'spark'.

你已准备好开始进行交互式工作!

请注意, SparkContext已被初始化。你无需从pyspark导入SparkContext即可开始工作。

当然, 你可以根据要更改的选项调整命令以启动Spark Shell。在以下命令中, 你将看到–master参数允许你指定SparkContext连接到哪个主机。在这种情况下, 你会看到本地模式已激活。括号之间的数字表示正在使用的内核数。在这种情况下, 将使用所有内核, 而local [4]将仅使用四个内核。


$ ./bin/pyspark --master local[*]

请注意, 应用程序用户界面位于localhost:4040。打开浏览器, 粘贴到该位置, 你将看到带有指示工作, 阶段, 存储等选项卡的仪表板。当你执行工作并对其进行调整时, 这无疑会派上用场。你将在后面进一步了解更多。

使用Jupyter Notebook运行Spark应用程序

下载Spark发行版后, 你也可以开始使用Jupyter Notebook。如果你想先尝试一下, 请转到此处, 确保单击” Welcome to Spark with Python”笔记本。该演示将向你展示如何使用Spark MLlib交互训练两个分类器, 以预测泰坦尼克号数据集中的幸存者。

在你的Jupyter Notebook中有多种选择可以获取Spark:你可以在Docker容器中运行PySpark笔记本, 可以使用Spark设置Jupyter Notebook, 或者可以确保在笔记本中添加可以使用它的内核。

无论如何, 请确保已准备好Jupyter Notebook应用程序。如果不这样做, 请考虑安装包含该应用程序的Anaconda, 或在pip pip3 install jupyter的帮助下进行安装。你可以在Docker容器中找到有关安装过程或使用Spark在Python中运行特定笔记本的更多信息, 请查阅srcmini的Jupyter Notebook权威指南。

Jupyter Notebook中的Spark

既然你已经具备了入门所需的一切, 则可以通过键入以下内容来启动Jupyter Notebook应用程序:


PYSPARK_DRIVER_PYTHON="jupyter" PYSPARK_DRIVER_PYTHON_OPTS="notebook" pyspark

或者, 你可以在导入PySpark之前, 用jupyter Notebook正常启动Jupyter Notebook并运行以下代码:


! pip install findspark 

使用findspark, 可以在运行时将pyspark添加到sys.path中。接下来, 你可以像导入其他常规库一样导入pyspark:


import findspark
findspark.init()

# Or the following command
findspark.init("/path/to/spark_home")

from pyspark import SparkContext, SparkConf

请注意, 如果你尚未将Brew安装在Spark上, 并且按照上面列出的说明进行操作, 则可能是需要将SPARK_HOME的路径添加到findspark.init()。如果你仍然不确定SPARK_HOME的位置, 可以调用findspark.find()来自动检测Spark的安装位置。

提示:你可以在此处阅读有关findspark的更多信息。

Jupyter笔记本和Spark内核

接下来, 如果要安装内核, 则要确保已安装Apache Toree。使用pip install toree通过pip安装Toree。接下来, 安装jupyter应用程序toree:


jupyter toree install --spark_home=/usr/local/bin/apache-spark/ --interpreters=Scala, PySpark

确保正确填写了spark_home参数, 并注意如果未在解释器参数中指定PySpark, 则默认情况下将安装Scala内核。该路径应指向你先前从Spark下载页面下载的解压缩目录。接下来, 验证内核是否包含在以下列表中:


jupyter kernelspec list

使用jupyter Notebook像往常一样启动Jupyter Notebook, 或者使用例如以下行进一步配置Spark:


SPARK_OPTS='--master=local[4]' jupyter notebook 

在其中指定使用4个线程在本地运行Spark。

在Docker容器中使用Jupyter运行PySpark

运行Jupyter Notebook应用程序的其他选项之一是在Docker容器中运行它。你所需要做的就是设置Docker并下载最适合你的项目的Docker映像。首先, 如果你还没有安装Docker, 请参阅本节中的Docker安装说明。

设置完成后, 转到DockerHub并获取类似jupyter / pyspark-notebook的图像, 以启动Jupyter中的PySpark之旅。对于其他图像, 请签出该存储库。

你是否希望更好地了解Jupyter项目的发展以及Jupyter Notebook的组件?考虑阅读我们的IPython或Jupyter吗?发布。

Spark API:RDD, 数据集和数据帧

对于刚刚熟悉Spark的任何人, 这三个API似乎都非常令人困惑。当我说有时候很难看到树木茂盛的森林时, 你会同意我的观点。本节着重于使这三者之间的区别更加清晰, 并说明何时应使用哪种API。

开发区

RDD是Spark的构建块。这是Spark公开的原始API, 几乎所有更高级别的API都分解为RDD。从开发人员的角度来看, RDD只是一组表示数据的Java或Scala对象。

RDD具有三个主要特征:它们是编译时类型安全的(它们具有类型!), 它们是惰性的, 并且它们基于Scala集合API。

RDD的优点是多方面的, 但也存在一些问题。例如, 构建效率低下的转换链很容易, 对于非JVM语言(例如Python)来说转换链很慢, 而Spark无法对其进行优化。最后, 很难理解与他们一起工作时发生了什么, 因为例如, 转换链的可读性不是很强, 因为你不会立即看到解决方案, 而是如何正在做。

数据框

由于使用RDD时可能会遇到的缺点, 因此想到了DataFrame API:它为你提供了更高级别的抽象, 允许你使用查询语言来处理数据。更高级别的抽象是表示数据和架构的逻辑计划。这意味着与你的数据进行交互的前端要容易得多!由于逻辑计划将转换为物理计划以执行, 因此实际上, 你与他们合作时的工作实际上更接近于自己在做的事情, 而不是尝试如何做, 因为你让Spark弄清楚了找出最有效的方式来做自己想做的事。

请记住, 尽管DataFrames仍建立在RDD之上!

正是因为你让Spark担心最有效的处理方式, 所以DataFrames得到了优化:在转换数据时将做出更明智的决策, 这也解释了为什么它们比RDD更快。

更具体地说, 性能的提高归因于两点, 在读取DataFrame时经常会遇到这些问题:自定义内存管理(Tungsten项目), 这将确保在CPU限制下, 你的Spark作业快得多;以及优化的执行计划(Catalyst优化器), DataFrame的逻辑计划是其中的一部分。

数据集

使用DataFrames的唯一缺点是, 在使用DataFrames时, 你失去了编译时类型的安全性, 这使你的代码更容易出错。这就是为什么他们更偏向于数据集的原因的一部分:重新获得一些类型安全性和lambda函数的使用, 这意味着你想稍微回到RDD必须提供的优势, 但是你不想失去DataFrames提供的所有优化。

Python中的Apache Spark:新手指南1

数据集的概念已经发展, 并且已成为除RDD API之外的第二个主要Spark API。因此, 数据集可以具有两个明显的特征:强类型API和非类型API。这意味着DataFrame在概念上仍然存在, 作为Dataset的同义词:任何DataFrame现在都是Scala中Dataset [Row]的同义词, 其中Row是通用的无类型JVM对象。数据集是强类型JVM对象的集合。

请注意, 由于Python没有编译时类型安全性, 因此仅未类型化的DataFrame API可用。换句话说, Spark数据集是静态类型的, 而Python是动态类型的编程语言。这就解释了为什么要在Python中使用Spark时, 可以使用DataFrames或未类型化的API。此外, 请记住, 数据集就像DataFrames一样, 是在RDD之上构建的。

总之, 使用DataSet API(包括DataSet和DataFrames)的明显优势是静态类型和运行时类型安全性, 对数据的更高级别抽象以及性能和优化。当然, 这也有助于DataSet API基本上迫使你使用结构化的数据, 这也增加了API本身的易用性。

什么时候使用?

上面所有这些都解释了为什么在使用PySpark时通常建议使用DataFrame, 也因为它们与DataFrame结构非常接近, 你可能已经从pandas库中知道了。还要注意, 以上部分已指出:由于缺少Python语言的编译时类型安全性, 因此Python中没有真正的数据集位置。但是, 这并不意味着同时包含强类型和非类型API的数据集API不会派上用场:当你想要使用高级表达式, SQL查询, 列访问和在半结构化数据上使用lambda函数。但是, 如果你仍然希望拥有更多控制权, 则可以始终使用RDD。

当你要对非结构化数据执行低级转换和操作时, 可以使用RDD。这意味着你不必担心在按名称或列处理或访问属性时强加模式。此外, 你不一定需要DataFrames和DataSet可以为(半)结构化数据提供的优化和性能优势。另外, 当你要使用功能性编程构造而不是特定于域的表达式来操纵数据时, 通常会使用RDD。

简而言之, 请使用最适合你的用例的API, 但还要记住, 从DataFrame切换到RDD相当容易, 这将在下一部分中看到!

Spark DataFrame和Pandas DataFrame之间的区别

DataFrame通常与关系数据库中的表或R或Python中的数据框架进行比较:它们具有一种方案, 具有列名和类型以及行和列的逻辑。这模仿了熊猫中DataFrames的实现!

请注意, 即使Spark, Python和R数据帧可以非常相似, 也存在很多差异:正如你在上面所读的, Spark DataFrames在后台进行了特定的优化, 并且可以使用分布式内存来处理大数据。 , 而Pandas DataFrames和R数据帧只能在一台计算机上运行。

但是, 这些差异并不意味着它们两者不能一起工作:你可以重复使用现有的Pandas DataFrame, 以扩展到更大的数据集。如果要将Spark DataFrame转换为Pandas DataFrame, 并且希望生成的Pandas DataFrame较小, 则可以使用以下代码行:


df.toPandas() 

你会看到, 两者很好地集成在一起:借助Spark DataFrame, 你可以并行化工作负载, 可以利用Python和R DataFrames必须提供的大量库, 这使可视化或机器学习变得更加容易!

请注意, 你确实需要确保DataFrame足够小, 因为所有数据都已加载到驱动程序的内存中!

RDD行动与变革

RDD支持两种类型的操作:转换(从现有操作创建新数据集)和动作(在操作数据集上执行计算后将值返回到驱动程序)。例如, map()是一个转换, 它将每个数据集元素通过一个函数传递, 并返回代表结果的新RDD。另一方面, reduce()是使用某些函数聚合RDD的所有元素并将最终结果返回给驱动程序的操作。但是请注意, 还有一个reduceByKey()返回分布式数据集。

Spark中的所有转换都是惰性的, 因为它们不会立即计算出结果:相反, 它们只是记住应用于某些基本数据集的转换。仅当动作要求将结果返回给驱动程序时才计算转换。

使用这两种RDD操作, Spark可以更有效地运行:通过map()操作创建的数据集将在随后的reduce()操作中使用, 并且只会将最后一个reduce函数的结果返回给驱动程序。这样, 缩小的数据集而不是较大的映射数据集将返回给用户。毫无疑问, 这更有效!

为什么需要缓存或保留RDD?

默认情况下, 每次在其上执行操作时, 都可能会重新计算每个转换后的RDD。但是, 你也可以使用persist(或缓存)方法将RDD保留在内存中, 在这种情况下, Spark会将元素保留在群集中, 以便下次查询时可以更快地进行访问。还支持将RDD持久存储在磁盘上, 或在多个节点之间复制。

迭代算法的使用和快速交互式RDD的使用是用于缓存或持久保留RDD的几个用例。

如果要保留RDD, 请查看要定义的持久性级别。你可以在这里找到更多信息。

持久还是广播变量?

RDD分为多个分区:每个分区都可以视为整个RDD的不变子集。当你执行Spark程序时, 每个分区都会发送给工作程序。这意味着每个工作人员都对数据的子集进行操作。如果需要重新声明RDD, 则每个工作程序都可以缓存数据:详细说明的分区存储在内存中, 并将在其他操作中重用。正如你在上一段中所阅读的那样, 通过持久化, 下一次操作使用Spark时, Spark将可以更快地访问该数据分区。

但是, 请记住, 将函数传递给Spark操作时, 该函数在单独的群集节点上执行。每个节点都在函数内部收到变量的副本, 因此对变量的本地值的每次更改都不会传播到驱动程序。

可能会发生这种情况的典型用例是, 当你要对小表执行查询以将其与较大的数据连接在一起时, 必须重新分配操作的中间结果(例如经过训练的模型)或静态查找表组。

你无需使用广播变量为每台计算机创建变量的副本, 而是使用广播变量向每个工作者一次发送一些不可变状态。广播变量允许程序员在每台计算机上保留一个缓存的只读变量。简而言之, 当你需要变量的本地副本时, 可以使用这些变量。

你可以使用SparkContext.broadcast(variable)创建一个广播变量。这将返回广播变量的引用。

如你所见, 持久保留RDD或使用广播变量是针对不同问题的两种不同解决方案。

什么是Spark最佳实践?

当你使用PySpark时, 可能会有无数的机会, 但这并不意味着你可以遵循一些简单而通用的最佳实践:

使用Spark DataFrames

考虑上面的部分, 查看是否应使用RDD或DataFrame。如前所述, Spark DataFrame是经过优化的, 因此也比RDD更快。特别是在使用结构化数据时, 你应该真正考虑将RDD切换到DataFrame。

RDD最佳做法

不要在大型​​RDD上调用collect()

通过在任何RDD上调用collect(), 你可以将数据从节点拖回到应用程序中。每个RDD元素都将复制到单个驱动程序中, 这将耗尽内存并崩溃。考虑到你想以尽可能高效的方式使用Spark的事实, 在大型RDD上调用collect()并不是一个好主意。

你可以用来检查数据的其他函数是take()或takeSample(), 但countByKey(), countByValue()或collectAsMap()可以为你提供帮助。如果确实需要查看完整的数据, 则始终可以将RDD写出到文件中, 或将其导出到足够保留数据的数据库中。

加入前降低RDD

当你使用Spark RDD时, 可以进行链式操作非常方便, 但是你可能没有意识到, 你也有责任构建高效的转换链。照顾效率也是调整Spark作业的效率和性能的一种方式。

修改已记录的操作链时, 可以应用的最基本规则之一是, 确保在加入数据之前过滤或减少数据。这样, 你就可以避免在网络上发送过多的数据, 而这些数据在加入后将被丢弃, 这已经是一个很好的理由了, 对吧?

但是还有更多。联接操作是你可以在Spark中使用的最昂贵的操作之一, 因此这就是要提防这一点的原因。当在联接之前减少数据时, 可以避免将数据乱码太多。

避免在大型RDD上使用groupByKey()

在大数据集上, 最好使用其他功能, 例如reduceByKey(), combiningByKey()或foldByKey()。当你使用groupByKey()时, 所有键值对在群集中都会随机排列。许多不必要的数据正在通过网络传输。此外, 这还意味着, 如果在一台计算机上重新整理的数据量超出了内存容量, 则数据将泄漏到磁盘上。这会严重影响Spark作业的性能。

例如, 当你使用reduceByKey()时, 在重排数据之前已经合并了具有相同键的对。因此, 你将不得不通过网络发送更少的数据。接下来, 再次调用reduce函数, 以便减少每个分区中的所有值。

广播变量

由于你已经知道什么是广播变量以及在什么情况下可以派上用场, 因此你还将了解到这是使用Spark时的最佳实践之一, 因为你可以减少启动工作的成本在集群上。

避免使用flatmap(), join()和groupBy()模式

当你有两个按键分组的数据集并且想要加入它们但仍将它们分组时, 请使用cogroup()而不是上述模式。

Spark用户界面

你已经在上面的部分内容中了解了它, 但是使用Spark UI确实是你不能错过的事情。通过此Web界面, 你可以在Web浏览器中监视和检查作业的执行情况, 如果你想对作业进行控制, 这非常重要。

Spark UI允许你维护活动, 已完成和失败的作业的概览。你可以看到提交作业的时间以及该作业的运行时间。除了原理图概述之外, 你还可以在”任务”选项卡中查看事件时间线部分。通过单击作业本身, 确保还找到有关你作业的更多信息。你将获得有关其中任务阶段的更多信息。

用户界面中的”阶段”选项卡显示了Spark应用程序中所有作业的所有阶段的当前阶段, 而”存储”选项卡将为你提供有关RDD大小和内存使用情况的更多信息。

如何关闭PySpark日志记录

进入Spark目录, 执行以下命令:


cp conf/log4j.properties.template conf/log4j.properties

请注意, 此命令将文件log4j.properties.template复制到相同的文件夹conf中, 但使用不同的名称, 即log4j.properties, 而不是原始名称log4j.properties.template。接下来, 你还应该知道Apache Log4j是基于Java的日志记录实用程序。简而言之, 你正在复制日志记录模板。

接下来, 在开始编辑任何内容之前, 请花一些时间使用文本编辑器检查模板文件log4j.properties.template。你会看到以下部分:


# Set everything to be logged to the console
log4j.rootCategory=INFO, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n

你会看到默认情况下, log4j rootCategory属性设置为INFO。这意味着你将看到INFO级别的日志, 并提供”以粗粒度级别突出显示应用程序进度的信息性消息”。不难想象, 这种级别的日志记录可以为你提供许多(如果不是太多的话)日志。但是, 完全关闭日志记录通常也不是一个好选择, 因为你通常希望始终与应用程序在做的事情保持同步:这使得调试或发现异常过早变得容易得多。

考虑将级别设置为WARN, 这将指示日志中潜在的有害情况, 或者将ERROR指示可能不会阻止应用程序运行的错误事件。你可以在这里找到其他级别。

现在你知道该怎么做:用nano log4j.properties或vim编辑log4j.properties, 并用所需的日志记录级别替换INFO。

正确保存文件, 然后重新启动Shell。再次运行该应用程序, 你会发现日志记录已减少到你在属性文件中定义的级别。

激发你的数据分析!

你已经到了本教程的结尾, 因此, 如果你只是阅读但不遵循本教程, 现在是时候开始使用Spark!

如果你想了解有关PySpark的更多信息, 请考虑参加srcmini的PySpark入门课程。

赞(0) 打赏
未经允许不得转载:srcmini » Python中的Apache Spark:新手指南
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

微信扫一扫打赏