文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

扩展 Spark SQL 解析,你知道吗?

2024-12-03 06:25

关注

大家好久不见了,最近生活发生了很多变故,同时我也大病了一场,希望一切都尽快好起来吧。今天跟大家分享下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)

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

  1. stat:   expr NEWLINE               # printExpr 
  2.   |   ID '=' expr NEWLINE         # assign 
  3.   |   NEWLINE                     # blank 
  4.   ; 
  5.  
  6. expr:   expr op=('*'|'/') expr     # MulDiv 
  7.   |   expr op=('+'|'-') expr     # AddSub 
  8.   |   INT                         # int 
  9.   |   ID                         # id 
  10.   |   '(' expr ')'               # parens 
  11.   ; 

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

完整语法文件:

  1. grammar LabeledExpr; // rename to distinguish from Expr.g4 
  2.  
  3. prog:   stat+ ; 
  4.  
  5. stat:   expr NEWLINE               # printExpr 
  6.   |   ID '=' expr NEWLINE         # assign 
  7.   |   NEWLINE                     # blank 
  8.   ; 
  9.  
  10. expr:   expr op=('*'|'/') expr     # MulDiv 
  11.   |   expr op=('+'|'-') expr     # AddSub 
  12.   |   INT                         # int 
  13.   |   ID                         # id 
  14.   |   '(' expr ')'               # parens 
  15.   ; 
  16.  
  17. MUL :   '*' ; // assigns token name to '*' used above in grammar 
  18. DIV :   '/' ; 
  19. ADD :   '+' ; 
  20. SUB :   '-' ; 
  21. ID :   [a-zA-Z]+ ;     // match identifiers 
  22. INT :   [0-9]+ ;         // match integers 
  23. NEWLINE:'\r''\n' ;     // return newlines to parser (is end-statement signal) 
  24. WS :   [ \t]+ -> skip ; // toss out whitespace 

SqlBase.g4

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

 

扩展语法定义

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

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

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

 

现在我们添加一个 jackyExpression

 

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

 

将 JACKY 添加为token

 

修改语法文件 如下:

  1. jackyExpression 
  2.   : JACKY'(' number ')' 
  3.   //expression 
  4.   ; 
  5.  
  6. namedExpression 
  7.   : expression (AS? (identifier | identifierList))? 
  8.   ; 
  9.  
  10. namedExpressionSeq 
  11.   : namedExpression (',' namedExpression | jackyExpression )* 
  12.   ; 

扩展逻辑计划

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

 

Spark 执行流程

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

 

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

 

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

  1.  override def visitJackyExpression(ctx: JackyExpressionContext): String = withOrigin(ctx) { 
  2.    println("this is astbuilder jacky = "+ctx.number().getText) 
  3.  
  4.    this.jacky = ctx.number().getText.toInt 
  5.  
  6.    ctx.number().getText 

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

  1. // Expressions. 
  2.    val expressions = Option(namedExpressionSeq).toSeq 
  3.     .flatMap(_.namedExpression.asScala) 
  4.     .map(typedVisit[Expression]) 
  5.  
  6.  
  7. //jackyExpression 处理 
  8.    if(namedExpressionSeq().jackyExpression()!=null && namedExpressionSeq().jackyExpression().size() > 0){ 
  9.      visitJackyExpression(namedExpressionSeq().jackyExpression().get(0)) 
  10.   } 

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

测试

测试用例

  1. public class Case4 { 
  2.    public static void main(String[] args) { 
  3.        CharStream ca = CharStreams.fromString("SELECT `b`.`id`,`b`.`class` JACKY(2) FROM `b` LIMIT 10"); 
  4.        SqlBaseLexer lexer = new SqlBaseLexer(ca); 
  5.        SqlBaseParser sqlBaseParser = new SqlBaseParser(new CommonTokenStream(lexer)); 
  6.        ParseTree parseTree = sqlBaseParser.singleStatement(); 
  7.  
  8.        AstBuilder astBuilder = new AstBuilder(); 
  9.        astBuilder.visit(parseTree); 
  10.        System.out.println(parseTree.toStringTree(sqlBaseParser)); 
  11.        System.out.println(astBuilder.jacky()); 
  12.   } 

执行结果

本文转载自微信公众号「麒思妙想」,可以通过以下二维码关注。转载本文请联系麒思妙想公众号。

 

来源:麒思妙想内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯