2.3 Spark 2.4 SQL
Spark 2.0通过对SQL 2003的支持增强了SQL功能,Catalyst新引擎提升了Spark查询优化的速度;本节对DataFrame和Dataset API、时间窗口进行了讲解。
在Apache Spark 2.2.X版本的基础上,Apache Spark 2.3.X版本、Apache Spark 2.4.X版本中核心和Spark SQL的主要更新如下。
1.API更新
SPARK-18278:Spark基于Kubernetes。一个新的Kubernetes调度器后端,支持将Spark作业提交到Kubernetes进行集群管理。这种支持目前是实验性的,应该对配置、容器映像和入口点进行更改。
SPARK-16060:矢量化ORC阅读器。增加了对新ORC阅读器的支持,通过矢量化(2~5倍)大大提高了ORC扫描吞吐量。要启用阅读器,用户可以将spark.sql.orc.impl设置为native。
SPARK-18085:Spark History Server V2。一个新的Spark History Server(SHS)后端,通过更高效的事件存储机制为大规模应用程序提供更好的可扩展性。
SPARK-15689、SPARK-22386:Data Source API V2。在Spark中插入新数据源的实验API。新的API试图解决V1版本API的几个局限性,旨在促进高性能、易于维护和可扩展的外部数据源的开发。此API仍在进行开发。
SPARK-22216、SPARK-21187:通过快速数据序列化和矢量化执行显著提高了Python的性能和互操作性。
SPARK-26266:对Scala 2.12.8更新(需要最近的Java 8版本)。
SPARK-26188:Spark 2.4.0分区行为打破向后兼容性。
SPARK-27198:driver和executor中的心跳间隔不匹配。
SPARK-24374:屏障执行模式。在调度器中支持屏障执行模式,更好地与深度学习框架集成。
SPARK-14220:可以使用Scala 2.12构建Spark,并在Scala 2.12中编写Spark应用程序。
SPARK-23899:高阶函数。添加许多新的内置函数,包括高阶函数,以便更容易地处理复杂的数据类型。
SPARK-24768:内置AVRO数据源。内嵌Spark-Avro包,具有逻辑类型支持、更好的性能和可用性。
SPARK-24035:透视转换的SQL语法。
SPARK-24940:用于SQL查询的Coalesce和Repartition提示。
SPARK-19602:支持完全限定列名的列解析。
SPARK-21274:实现EXCEPT ALL及INTERSECT ALL。
2.性能优化和系统稳定性
SPARK-21975:基于成本的优化器中的直方图支持。
SPARK-20331:更好地支持Hive分区修剪的谓词下推。
SPARK-19112:支持ZStandard标准压缩编解码器。
SPARK-21113:支持预读输入流在溢出读取器中分摊磁盘I/O成本。
SPARK-22510、SPARK-22692、SPARK-21871:进一步稳定codegen框架,以避免Java方法和Java编译器常数池受到64KB JVM字节码限制。
SPARK-23207:修复了Spark中一个长期存在的BUG,在这种情况下,数据帧上的连续洗牌+重新分区可能导致某些案例的不正确。
SPARK-22062、SPARK-17788、SPARK-21907:解决OOM的各种原因。
SPARK-22489、SPARK-22916、SPARK-22895、SPARK-20758、SPARK-22266、SPARK-19122、SPARK-22662、SPARK-21652:基于规则的优化器和规划器中的增强功能。
SPARK-26080:无法在Windows上运行worker.py。
SPARK-27419:如果设置值spark.executor.heartbeatinterval少于1秒,将经常失败,因为值将被转换为0,心跳将始终超时,最终杀死executor。
SPARK-25535:解决常见加密中的错误检查。
SPARK-26891:RequestExecutors反映节点黑名单并可序列化。
SPARK-27496:RPC返回致命错误。
SPARK-27544:修复Python测试脚本以在Scala 2.12版本上工作。
SPARK-27469:将commons beanutils更新为1.9.3。
SPARK-16406:大量列的引用解析应该更快。
SPARK-23486:lookupFunctions从外部目录缓存函数名以查找函数。
SPARK-23803:支撑桶修剪。
SPARK-24802:优化规则排除。
SPARK-4502:Parquet表的嵌套方案修剪。
SPARK-24296:支持大于2GB的复制块。
SPARK-24307:支持从内存发送超过2GB的消息。
SPARK-23243:随机洗牌+对RDD重新分区可能导致错误答案。
SPARK-25181:限制了BlockManager主线程池和从线程池的大小,在网络速度较慢时降低了内存开销。
3.更新变化
SPARK-22036:默认情况下,如果无法精确表示,小数之间的算术运算将返回舍入值(以前的版本中返回空值)。
SPARK-22937:当所有输入都是二进制的时候,sql elt()返回一个二进制输出。否则将作为字符串返回。在以前的版本中,不管输入类型如何,总是以字符串形式返回。
SPARK-22895:如果可能,在第一个非确定性谓词之后的连接/筛选器的确定性谓词也会向下通过子运算符推送。在以前的版本中,这些过滤器不符合谓词下推的条件。
SPARK-22771:当所有输入都是二进制的时候,functions.concat()返回一个二进制输出。否则,它将作为字符串返回。在以前的版本中,不管输入类型如何,它总是以字符串形式返回。
SPARK-22489:当任何一个join端可以广播时,广播提示中显式指定的表。
SPARK-22165:分区列推断以前发现不同推断类型的公共类型不正确,例如,以前它以double类型作为double类型和date类型的公共类型结束,现在,它为此类冲突找到了正确的通用类型。
SPARK-22100:percentile_approx函数以前接受numeric数字类型输入,并输出double类型结果。现在支持日期类型、时间戳类型和数字类型作为输入类型,结果类型也更改为与输入类型相同,这对百分位数更为合理。
SPARK-21610:当引用的列只包含内部损坏记录列(默认情况下名为“损坏记录”)时,不允许从原始JSON/CSV文件查询。相反,可以缓存或保存解析的结果,然后发送相同的查询。
SPARK-23421:Spark 2.2.1和2.3.0,当数据源表具有同时存在于分区模式和数据模式中的列时,总是在运行时推断模式。推断模式没有分区列。读取表时,Spark将查询这些重叠列的分区值,而不是数据源文件中存储的值。在2.2.0和2.1.X版本中,推断的模式是分区的,但用户看不到表的数据(结果集为空)。
SPARK-19732:na.fill()或fillna也接受布尔值,并用布尔值替换空值。在以前的Spark版本中,pyspark只是忽略它并返回原始的数据集/数据帧。
SPARK-22395:Pandas 0.19.2或更高版本需要使用Pandas相关功能,如toPandas、从Pandas DataFrame创建数据帧等。
SPARK-22395:与panda相关功能的时间戳值的行为已更改为会话时区,这在以前的版本中被忽略。
SPARK-23328:在to_replace不是字典时,df.replace不允许省略值。以前,值在其他情况下可以省略,默认情况下没有值,这是反直觉的,并且容易出错。
SPARK-20236:支持Hive动态分区覆盖语义。
SPARK-4131:支持INSERT OVERWRITE DIRECTORY,直接从查询将数据写入文件系统。
SPARK-19285、SPARK-22945、SPARK-21499、SPARK-20586、SPARK-20416、SPARK-20668:UDF增强。
SPARK-20463、SPARK-19951、SPARK-22934、SPARK-21055、SPARK-17729、SPARK-20962、SPARK-20963、SPARK-20841、SPARK-17642、SPARK-22475、SPARK-22934:改进了ANSI SQL兼容性和Hive兼容性。
SPARK-20746:更全面的SQL内置函数。
SPARK-21485:为内置函数生成Spark SQL文档。
SPARK-19810:移除对Scala 2.10的支持。
SPARK-22324:将Arrow升级到0.8.0,neNetty升级到4.1.17。
SPARK-25250:可能导致job永久挂起,将在2.4.2中恢复。
SPARK-24935:从Spark 2.2开始执行Hive UDF时出现问题。
SPARK-27539:修复包含空值的列的聚合输出行估计不准确的问题。
SPARK-27563:自动获取HiveExternalCatalogVersionsSuite中的最新Spark版本。
SPARK-24596:非级联缓存无效。
SPARK-23880:不触发任何用于缓存数据的作业。
SPARK-23510:支持Hive 2.2和Hive 2.3元存储。
SPARK-23711:为UnsafeProjection添加fallback生成器。
SPARK-24626:Analyze Table命令中的并行位置大小计算。
4.Bug修复
SPARK-26961:在Spark Driver中发现Java级死锁。
SPARK-26998:在独立模式下执行executor进程时,spark.ssl.keyStorePassword在“ps -ef”输出是明文形式。
SPARK-27216:将RoaringBitmap升级到0.7.45以修复kryo不安全的ser/dser问题。
SPARK-27244:使用选项logconf=true时修改密码。
SPARK-27267:Snappy 1.1.7.1在解压缩空的序列化数据时失败。
SPARK-27275:EncryptedMessage.transferTo的潜在损坏。
SPARK-27301:DStreamCheckpointData无法清除,因为它的文件系统已缓存。
SPARK-27338:TaskMemoryManager和UnsafeExternalSorter$SpillableIterator之间的死锁。
SPARK-27351:AggregateEstification之后的输出行估计错误,只有空值列。
SPARK-27390:修复包名不匹配。
SPARK-27394:当没有任务开始或完成时,UI的过时可能会持续几分钟或几小时。
SPARK-27403:修复updateTableStats,更新表状态时始终使用新状态或不使用任何状态。
SPARK-27406:当两台机器的oops大小不同时,UnsafeArrayData序列化将中断。
SPARK-27453:DSv1将自动删除DataFrameWriter.partitionBy。
SPARK-25271:带Hive parquet的CTA应利用本地parquet源。
SPARK-25879:选择嵌套字段和顶级字段时模式修剪失败。
SPARK-25906:spark shell无法正确处理-i选项。
SPARK-25921:Python worker重用导致屏障任务在没有BarrierTaskContext的情况下运行。
SPARK-25918:LOAD DATA LOCAL INPATH应处理相对路径。
5.改进
SPARK-27346:更新断言examples表达式中的字段信息。
SPARK-27358:将jquery更新为1.12.X,以获取安全修补程序。
SPARK-27479:隐藏API文档org.apache.spark.util.kvstore。
SPARK-23523:规则OptimizeMetadataOnlyQuery导致的结果不正确。
SPARK-23406:stream-stream self-joins的Bugs。
SPARK-25088:rest服务器默认值和文档更新。
SPARK-23549:比较时间戳和日期时强制转换为时间戳。
SPARK-24324:Pandas Grouped Map UDF应按名称分配结果列。
SPARK-23425:使用通配符加载HDFS文件路径的数据工作不正常。
SPARK-23173:from_json可以为标记为不可为空的字段生成空值。
SPARK-24966:为集合操作实现优先规则。
SPARK-25708:Having没有group by的应该是全局聚合。
SPARK-24341:正确处理子查询中的多值。
SPARK-19724:使用现有默认位置创建托管表应引发异常。
6.任务
SPARK-27382:更新Spark 2.4.X测试HiveExternalCatalogVersionsSuite。
SPARK-23972:将Parquet从1.8.2更新为1.10.0。
SPARK-25419:Parquet谓词下推改进。
SPARK-23456:本机ORC阅读器默认为打开状态。
SPARK-22279:默认情况下,使用本机ORC阅读器读取Hive serde表。
SPARK-21783:默认情况下打开ORC过滤器下推。
SPARK-24959:JSON和CSV的加速计数方法count()。
SPARK-24244:解析csv分析器所需的列。
SPARK-23786:csv模式验证不检查列名。
SPARK-24423:用于指定从JDBC读取的查询的选项。
SPARK-22814:支持JDBC分区列中的日期/时间戳。
SPARK-24771:将avro从1.7.7更新为1.8。
SPARK-23984:用于kubernetes的pyspark绑定。
SPARK-24433:kubernetes的R绑定。
SPARK-23146:支持kubernetes集群后端的客户端模式。
SPARK-23529:支持安装kubernetes卷。
SPARK-24215:实现对数据帧API的热切评估。
SPARK-22274:Pandas UDF的用户定义聚合函数。
SPARK-22239:Pandas UDF的用户定义窗口函数。
SPARK-24396:为Python添加结构化流式ForeachWriter。
SPARK-23874:将Apache Arrow升级到0.10.0。
SPARK-25004:增加spark.executor.pyspark.memory限制。
SPARK-23030:使用Arrow stream格式创建和收集Pandas DataFrames。
SPARK-24624:支持Python UDF和scalar Pandas UDF的混合。
2.3.1 Spark SQL
Spark 2.0通过对SQL 2003的支持大幅增强了SQL功能,现在可以运行所有99个TPC-DS查询。这个版本中的SparkSQL主要有以下几点改进。
(1)引入了支持ANSISQL和HiveSQL的本地解析器。
(2)本地实现DDL命令。
(3)支持非相关标量子查询。
(4)在Where与having条件中,支持(not)in和(not)exists。
(5)即使Spark没有和Hive集成搭建,SparkSQL也支持它们一起搭建时的除了Hive连接、Hive UDF(User Defined Function用户自定义函数)和脚本转换之外的大部分功能。
(6)Hive式的分桶方式的支持。
另外,Catalyst查询优化器对于常见的工作负载也有了很多提升,对如nullability propagation之类的查询做了更好的优化。Catalyst查询优化器从最早的应用于SparkSQL到现在应用于DataSetAPI,对Spark程序的高效率运行起到了非常重要的作用,并且随着DataSetAPI的流行,以及优化器自身的不断演进,未来肯定会对Spark的所有框架带来更高的执行效率。
2.3.2 DataFrame和Dataset API
在Spark 1.X版本中,DataFrame的API存在很多问题,如DataFrame不是类型安全的(not type-safe)、不是面向对象的(not object-oriented),为了克服这些问题,Spark在1.6版本引入了Dataset,并在2.0版本的Scala和Java中将二者进行了统一(在Python和R中,由于缺少类型安全性,DataFrame仍是主要的编程接口),DataFrame成为DataSet[Row]的别名,而且Spark 2.0版本为DataSet的类型化聚合加入了一个新的聚合器,让基于DataSet的聚合更加高效。
在Spark 2.X版本中,DataFrame和Dataset API晋升为稳定的API。也就是说,可以在生产实践中使用它们,且后续会基于向后兼容的前提不断强化。
DataSetAPI是High-LevelAPI,有更高的抽象级别,与RDDAPI这样的Low-LevelAPI相比更加易用,它对于提升用户的工作效率,以及提高程序的可读性而言意义非凡。由于WholeStageCodeGeneration的引入,SparkSQL和DataSetAPI中的常见算子的性能提升了2~10倍。加上Catalyst查询优化器和Tungsten的帮助,用户不用过多地关注对程序的优化,也能获得很好的执行效率。
所以,毋庸置疑地,这样一种简单高效的API将成为Spark未来主流的编程接口。
2.3.3 Timed Window
对于经常用到复杂SQL的用户而言,窗口函数一直以来都是不可或缺的,在Spark 2.X版本中,通过对Hive中的窗口函数的本地化实现,使用Spark的内存管理机制,从而提升了窗口函数的性能。