扩展 Spark SQL 解析

大家好久不见了,最近生活发生了很多变故,同时我也大病了一场,希望一切都尽快好起来吧。今天跟大家分享下Spark吧,谈谈如何修改Spark SQL解析,让其更符合你的业务逻辑。好,我们开始吧...

理论基础

ANTLR

Antlr4是一款开源的语法分析器生成工具,能够根据语法规则文件生成对应的语法分析器。现在很多流行的应用和开源项目里都有使用,比如Hadoop、Hive以及Spark等都在使用ANTLR来做语法分析。

ANTLR 语法识别一般分为二个阶段:

1.词法分析阶段 (lexical analysis)

对应的分析程序叫做 lexer ,负责将符号(token)分组成符号类(token class or token type)

2.解析阶段

根据词法,构建出一棵分析树(parse tree)或叫语法树(syntax tree)

ANTLR的语法文件,非常像电路图,从入口到出口,每个Token就像电阻,连接线就是短路点。

语法文件(*.g4)

上面截图对应的语法文件片段,定义了两部分语法,一部分是显示表达式和赋值,另外一部分是运算和表达式定义。

stat:   expr NEWLINE                # printExpr
    |   ID '=' expr NEWLINE         # assign
    |   NEWLINE                     # blank
    ;

expr:   expr op=('*'|'/') expr      # MulDiv
    |   expr op=('+'|'-') expr      # AddSub
    |   INT                         # int
    |   ID                          # id
    |   '(' expr ')'                # parens
    ;

接下来,加上定义词法部分,就能形成完整的语法文件。

完整语法文件:

grammar LabeledExpr; // rename to distinguish from Expr.g4

prog:   stat+ ;

stat:   expr NEWLINE                # printExpr
    |   ID '=' expr NEWLINE         # assign
    |   NEWLINE                     # blank
    ;

expr:   expr op=('*'|'/') expr      # MulDiv
    |   expr op=('+'|'-') expr      # AddSub
    |   INT                         # int
    |   ID                          # id
    |   '(' expr ')'                # parens
    ;

MUL :   '*' ; // assigns token name to '*' used above in grammar
DIV :   '/' ;
ADD :   '+' ;
SUB :   '-' ;
ID  :   [a-zA-Z]+ ;      // match identifiers
INT :   [0-9]+ ;         // match integers
NEWLINE:'\r'? '\n' ;     // return newlines to parser (is end-statement signal)
WS  :   [ \t]+ -> skip ; // toss out whitespace

SqlBase.g4

Spark的语法文件,在sql下的catalyst模块里,如下图:

扩展语法定义

一条正常SQL,例如 Select t.id,t.name from t  , 现在我们为其添加一个 JACKY表达式,令其出现在 Select 后面 ,形成一条语句

Select t.id,t.name JACKY(2) from t

我们先看一下正常的语法规则:

现在我们添加一个 jackyExpression

jackExpression 本身的规则就是 JACKY加上括号包裹的一个数字

将 JACKY 添加为token

修改语法文件 如下:

jackyExpression
    : JACKY'('  number ')'
    //expression
    ;

namedExpression
    : expression (AS? (identifier | identifierList))?
    ;

namedExpressionSeq
    :  namedExpression (',' namedExpression | jackyExpression )*
    ;

扩展逻辑计划

经过上面的修改,就可以测试语法规则,是不是符合预期了,下面是一颗解析树,我们可以看到jackyExpression已经可以正常解析了。

Spark 执行流程

这里引用一张经典的Spark SQL架构图

我们输入的 SQL语句 首先被解析成 Unresolved Logical Pan ,对应的是

给逻辑计划添加遍历方法:

  override def visitJackyExpression(ctx: JackyExpressionContext): String = withOrigin(ctx) {
    println("this is astbuilder jacky = "+ctx.number().getText)

    this.jacky = ctx.number().getText.toInt

    ctx.number().getText
  }

再处理namedExpression的时候,添加jackyExpression处理

    // Expressions.
    val expressions = Option(namedExpressionSeq).toSeq
      .flatMap(_.namedExpression.asScala)
      .map(typedVisit[Expression])


    //jackyExpression 处理
    if(namedExpressionSeq().jackyExpression()!=null && namedExpressionSeq().jackyExpression().size() > 0){
      visitJackyExpression(namedExpressionSeq().jackyExpression().get(0))
    }

好了,到这里从逻辑计划处理就完成了,有了逻辑计划,就可以在后续物理计划中添加相应的处理逻辑就可以了(还没研究明白... Orz)。

测试

测试用例

public class Case4 {
    public static void main(String[] args) {
        CharStream ca = CharStreams.fromString("SELECT  `b`.`id`,`b`.`class` JACKY(2)  FROM `b` LIMIT 10");
        SqlBaseLexer lexer = new SqlBaseLexer(ca);
        SqlBaseParser sqlBaseParser = new SqlBaseParser(new CommonTokenStream(lexer));
        ParseTree parseTree = sqlBaseParser.singleStatement();

        AstBuilder astBuilder = new AstBuilder();
        astBuilder.visit(parseTree);
        System.out.println(parseTree.toStringTree(sqlBaseParser));
        System.out.println(astBuilder.jacky());
    }
}

执行结果

关注 【 麒思妙想】解锁更多硬核。

历史文章导读

如果文章对您有那么一点点帮助,我将倍感荣幸

欢迎  关注、在看、点赞、转发 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
spark_sql语法是用于在Spark SQL中执行SQL查询和操作数据的语法。它支持常见的SQL语句,如SELECT、INSERT、UPDATE和DELETE,以及一些扩展功能,如使用UDF(User-Defined Function)进行自定义函数操作。通过执行spark.sql()方法,可以在Spark中执行SQL查询,并将结果以DataFrame的形式返回。此外,可以使用剥离的Parser模块查看Spark SQL语法解析后生成的语法树,这对于调试和优化SQL查询非常有用。要使用自定义函数,可以通过注册UDF将自定义函数添加到Spark SQL中,然后可以在SQL查询中使用它。例如,在Scala中可以使用spark.udf.register()方法注册一个自定义函数。总之,Spark SQL提供了丰富的语法和功能,可以方便地进行数据操作和分析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spark_SQL的UDF使用](https://blog.csdn.net/weixin_44018458/article/details/128800313)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [剥离的Parser模块,用于查看Spark SQL语法解析SQL后生成的语法树](https://download.csdn.net/download/qq_29235677/88114372)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麒思妙想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值