程序员大数据 爬虫Python AI Sql大数据,机器学习,人工智能

Antlr4 自定义实现SparkSQL的解析

2019-03-03  本文已影响51人  大猪大猪

Antlr4 是一个强大的解析器的生成器,可以用来读取、处理、执行或翻译结构化文本,ANTLR可以从语法上来生成一个可以构建和遍历解析树的解析器,最出名的Spark计算引擎2.x就是用它来解析SQL的,是一个牛到没朋友的家伙。

IDEA测试

IDEA语法分析插件
下载 antlr-v4-grammar-plugin

插件安装

antlr-v4-grammar分析插件

g4语法文件使用的是sparkSQL的SqlBase.g4的文件进行改造的 ArcSql.g4

右键选中 multiStatement 进行测试

antlr4

测试SQL语法树

antlr4-SQL-测试

生成解析配置

antlr4-生成解析代码
  1. 右键ArcSQL.g4文件,在下拉选项Configure ANTLR即可出来。
  2. 第一个Output directory...要写上输出代码的路径。
  3. 比如把它放到当前项目的antlr4的包中/dounine/github/arc/src/main/scala/com/dounine/arc/antlr4
  4. 右键ArcSQL.g4文件,选中Generate ANTLR Recognizer即可生成
  5. 会生成如下几个文件
ArcSQL.interp
ArcSQL.tokens
ArcSQLBaseListener
ArcSQLBaseVisitor
ArcSQLLexer
ArcSQLLexer.interp
ArcSQLLexer.tokens
ArcSQLListener
ArcSQLParser
ArcSQLVisitor

代码测试

依赖

compile group: 'org.antlr', name: 'antlr4', version: '4.7.2'

被动模式(树解析到节点了通知)

val loadLexer = new ArcSQLLexer(CharStreams.fromString(
      """
        select toUp(name) from log;
      """))
val tokens = new CommonTokenStream(loadLexer)
val parser = new ArcSQLParser(tokens)
val ctx = parser.multiStatement()
val listener = new ArcSQLBaseListener() {
      override def exitQuerySpecification(ctx: ArcSQLParser.QuerySpecificationContext): Unit = {
        val input = ctx.start.getTokenSource.asInstanceOf[ArcSQLLexer]._input
        val start = ctx.start.getStartIndex
        val stop = ctx.stop.getStopIndex
        val interval = new Interval(start, stop)
        val sqlText = input.getText(interval)
        println("表名 => " + ctx.tableAlias().strictIdentifier().getText)
        println("完整SQL =>" + sqlText)
      }
    }
ParseTreeWalker.DEFAULT.walk(listener, ctx)

输出(在ctx中还有很多关于sql树信息)

表名 => log
完整SQL =>select toUp(name) from log

主动模式(主动去要数据)

val vistor = new ArcSQLBaseVisitor[Unit] {

      override def visitQuerySpecification(ctx: QuerySpecificationContext): Unit = {
        val input = ctx.start.getTokenSource.asInstanceOf[ArcSQLLexer]._input
        val start = ctx.start.getStartIndex
        val stop = ctx.stop.getStopIndex
        val interval = new Interval(start, stop)
        val sqlText = input.getText(interval)
        println("表名 => " + ctx.tableAlias().strictIdentifier().getText)
        println("完整SQL =>" + sqlText)
      }
}
vistor.visit(ctx)
上一篇下一篇

猜你喜欢

热点阅读