在SQL的世界里,除了官方提供的常用的处理函数之外,一般都会提供可扩展的对外自定义函数接口,这已经成为一种事实的标准。
在前面Spark SQL源码分析之核心流程一文中,已经介绍了Spark SQL Catalyst Analyzer的作用,其中包含了ResolveFunctions这个解析函数的功能。但是随着Spark1.1版本的发布,Spark SQL的代码有很多新完善和新功能了,和我先前基于1.0的源码分析多少有些不同,比如支持UDF:
spark1.0及以前的实现:
-
protected[sql] lazy val catalog: Catalog = new SimpleCatalog -
@transient -
protected[sql] lazy val analyzer: Analyzer = -
new Analyzer(catalog, EmptyFunctionRegistry, caseSensitive = true) //EmptyFunctionRegistry空实现 -
@transient -
protected[sql] val optimizer = Optimizer
Spark1.1及以后的实现:
-
protected[sql] lazy val functionRegistry: FunctionRegistry = new SimpleFunctionRegistry //SimpleFunctionRegistry实现,支持简单的UDF -
@transient -
protected[sql] lazy val analyzer: Analyzer = -
new Analyzer(catalog, functionRegistry, caseSensitive = true)
一、引子:
对于SQL语句中的函数,会经过SqlParser的的解析成UnresolvedFunction。UnresolvedFunction最后会被Analyzer解析。
SqlParser:
除了非官方定义的函数外,还可以定义自定义函数,sql parser会进行解析。
-
ident ~ "(" ~ repsep(expression, ",") <~ ")" ^^ { -
case udfName ~ _ ~ exprs => UnresolvedFunction(udfName, exprs)
将SqlParser传入的udfName和exprs封装成一个class class UnresolvedFunction继承自Expression。
只是这个Expression的dataType等一系列属性和eval计算方法均无法访问,强制访问会抛出异常,因为它没有被Resolved,只是一个载体。
-
case class Unresolved

本文详细分析了Spark SQL中的用户自定义函数(UDF)注册和计算过程。在Spark SQL中,UDF首先通过SqlParser解析成UnresolvedFunction,然后在Analyzer阶段使用FunctionRegistry进行注册。UDFRegistration提供了registerFunction方法用于注册UDF,将Scala函数转化为Catalyst的Expression。在计算时,UDF作为Expression节点,通过反射调用scala函数进行实际计算。Spark的UDF实现简单,利用Scala函数的灵活性,提高了UDF的易用性和可读性。
最低0.47元/天 解锁文章
476

被折叠的 条评论
为什么被折叠?



