Apache Spark,惰性评估和多页SQL查询

著名的:spark与数据帧一起使用,这是转换算法。 该算法在最后一刻启动,以“给更多空间”进行优化,并通过优化使其尽可能高效地执行。


在削减的基础上,我们将分析如何将多页SQL查询分解为原子(不损失效率),以及由于该原因如何减少ETL管道的执行时间。


懒惰评估


spark的一个有趣的功能特性是惰性评估:仅在完成动作后才执行转换。 它是如何工作的(大致):在操作之前构建数据帧的算法被“粘在一起”,优化程序从他的角度构建最有效的最终算法,该算法开始并给出结果(操作所要求的结果)。


在我们的演示中,这里有趣的是:任何复杂的查询都可以分解为“原子”而不会降低效率。 让我们进一步分析。


多页SQL


我们编写“多页” SQL查询的原因有很多,这是主要的(可能是)不愿意创建中间对象(效率要求所支持的不满意)之一。 以下是一个相对复杂的查询的示例(当然,它甚至非常简单,但是为了进一步展示,我们将有足够的信息)。


qSel = """ select con.contract_id as con_contract_id, con.begin_date as con_begin_date, con.product_id as con_product_id, cst.contract_status_type_id as cst_status_type_id, sbj.subject_id as sbj_subject_id, sbj.subject_name as sbj_subject_name, pp.birth_date as pp_birth_date from kasko.contract con join kasko.contract_status cst on cst.contract_status_id = con.contract_status_id join kasko.subject sbj on sbj.subject_id = con.owner_subject_id left join kasko.physical_person pp on pp.subject_id = con.owner_subject_id """ dfSel = sp.sql(qSel) 

我们看到的是:


  • 从几个表中选择数据
  • 使用不同类型的联接
  • 可选列按选择部分,连接部分(以及其中的部分,但此处不在此处-为简单起见将其删除)分布

该查询可以分解成简单的查询(例如,首先将contract和contract_status表合并,将结果保存在临时表中,然后将其与subject合并,还将结果保存在临时表中,等等)。 当然,当我们创建非常复杂的查询时,便会执行此操作,然后-在调试后-将所有这些收集到一个多页块中。


这里有什么不好? 实际上,没有任何人像那样工作并且习惯了。


但是有缺点-或者说,有什么改进-请继续阅读。


火花中的相同查询


当然,在使用spark进行转换时,您可以只接受并执行此请求(这很好,事实上,我们也将执行它),但是您可以采用其他方法,让我们尝试一下。


让我们将此“复杂”查询分解为“原子”-基本数据帧。 我们将获得与查询中涉及的表数一样多的表(在本例中为4)。


它们是“原子”:


 dfCon = sp.sql("""select contract_id as con_contract_id, begin_date as con_begin_date, product_id as con_product_id, owner_subject_id as con_owner_subject_id, contract_status_id as con_contract_status_id from kasko.contract""") dfCStat = sp.sql("""select contract_status_id as cst_status_id, contract_status_type_id as cst_status_type_id from kasko.contract_status""") dfSubj = sp.sql("""select subject_id as sbj_subject_id, subject_type_id as sbj_subject_type_id, subject_name as sbj_subject_name from kasko.subject""") dfPPers = sp.sql("""select subject_id as pp_subject_id, birth_date as pp_birth_date from kasko.physical_person""") 

Spark允许您使用与实际“原子”分开的表达式将它们加入;让我们这样做:


 con_stat = f.col("cst_status_id")==f.col("con_contract_status_id") con_subj_own = f.col("con_owner_subject_id")==f.col("sbj_subject_id") con_ppers_own = f.col("con_owner_subject_id")==f.col("pp_subject_id") 

然后,我们的“复杂查询”将如下所示:


 dfAtom = dfCon.join(dfCStat,con_stat, "inner")\ .join(dfSubj,con_subj_own,"inner") \ .join(dfPPers,con_ppers_own, "left") \ .drop("con_contract_status_id","sbj_subject_type_id", "pp_subject_id","con_owner_subject_id","cst_status_id") 

这里有什么好? 乍一看,这没什么,反而相反:通过使用“复杂” SQL您可以了解正在发生的事情,通过我们的“原子”查询很难理解,您需要查看“原子”和表达式。


首先,请确保这些查询是相同的-在通过引用的jupyter书中,我给出了实现这两个查询的计划(好奇的人可以找到10个差异,但实质-等效-很明显)。 当然,这不是奇迹,而是奇迹(请参阅上面的惰性评估和优化)。


最后,我们拥有的-“多页”请求和“原子”请求以相同的效率工作(这很重要,没有进一步的考虑,部分会失去其含义)。


好了,现在让我们以构建查询的“原子”方式找到好处。


什么是“原子”(基本数据框)是我们对主题区域(关系表的一部分)的子集的了解。 通过隔离这样的“原子”,我们自动地(并且重要地,在算法上和可重复性)选择了我们称为“物理数据模型”的无边事物的重要部分。


加入时我们使用什么表达? 这也是有关主题区域的知识-这是主题区域的实体(数据库中的表)如何互连(如表达式中所示)的方式。


我重复一遍-这很重要-这种“知识”(原子和表达式)体现在可执行代码中(而不是在图或语言描述中),这是每次执行ETL管道时都要执行的代码(顺便说一句,该示例取自现实生活)。


我们从干净的编码器中知道,可执行代码是两个客观存在的工件之一,这些工件声称是文档的“标题”。 也就是说,“原子”的使用使我们在记录数据这样重要的过程中向前迈进了一步。


在“原子性”中还能找到什么?


输送机优化


在现实生活中,数据工程师-顺便说一句,我并没有介绍自己-ETL管道包括与上述类似的数十种转换。 表经常在其中重复(我以某种方式在Excel中进行了计算-40%的查询中使用了某些表)。


在效率方面会发生什么? 混乱-从源中读取同一张表多次...


如何改善呢? Spark具有一种用于缓存数据帧的机制-我们可以显式指定哪些数据帧以及要保留在缓存中的数据量。


为此,我们要做的是选择重复的表并以使总缓存大小最小化的方式构建查询(因为按照定义,所有表都不适合它,因此存在大数据)。


可以使用多页SSQ查询完成此操作吗? 是的,但是...有点复杂(我们实际上并没有数据帧,只有表格,也可以缓存它们-Spark社区正在为此工作)。


可以使用原子查询来完成吗? 是的 这并不困难,我们只需要概括“原子”,即可将管道中所有查询中使用的列添加到其中。 如果您考虑一下,从文档的角度来看,这是“正确的”:如果在某个查询中使用了列(即使在where部分中),则它是我们感兴趣的主题领域数据的一部分。


然后一切都变得很简单-我们缓存重复的原子(数据帧),构建转换链,以使所缓存的数据帧的交集最小(顺便说一下,这不是微不足道的,而是可算法化的)。


而且,我们可以完全“免费”获得最高效的输送机。 除此之外,有用且重要的工件是“准备”主题领域数据的文档记录。


机器人化与自动化


原子比“强大的SQL”更易于自动处理-原子的结构简单明了,spark可以为我们进行解析(为此特别感谢他),他还构建了查询计划,分析了查询计划,可以自动对查询处理的顺序进行重新排序。


因此,您可以在这里玩一些东西。


总结


也许我太乐观了-在我看来,此路径(查询原子化)比试图在事实之后描述数据源更有效。 另外-顺便说一下,“添加剂”的用途是什么-我们提高了效率。 为什么我认为原子方法“有效”? 这是常规过程的一部分,这意味着所描述的工件在长期内确实具有相关性。


我可能错过了一些东西-帮助找到(在评论中)?

Source: https://habr.com/ru/post/zh-CN481924/


All Articles