基于ANTLR4的大数据SQL编辑器解析引擎实践|得物技术

一、背景

随着得物离线业务的快速增长,为了脱离全托管服务的一些限制和享受技术发展带来的成本优化,公司提出了大数据Galaxy开源演进项目,将离线业务从全托管且封闭的环境迁移到一个开源且自主可控的生态系统中,而离线开发治理套件是Galaxy自研体系中一个核心的项目,在数据开发IDE中最核心的就是SQL编辑器,我们需要一个SQL解析引擎在SQL编辑提供适配得物自研Spark引擎的语法定义,实时语法解析,语法补全,语法校验等能力,结合业内dataworks和dataphin的实践,我们最终选用ANTLR作为SQL解析引擎底座。

二、ANTLR4 简介

ANTLR(一种语法解析引擎工具)是一个功能强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件。它广泛用于构建语言、工具和框架。ANTLR可以根据语法规则文件生成一个可以构建和遍历解析树的解析器。

ANTLR4 特性

ANTLR4 是一个强大的工具,适合用于语言处理、编译器构建、代码分析等多种场景。它的易用性、灵活性和强大的特性使得它成为开发者的热门选择。

  • 强大的文法定义:ANTLR4 允许用户使用简单且易读的文法语法来定义语言的结构。这使得创建和维护语言解析器变得更加直观,同时在复杂文法构造上支持左递归文法、嵌套结构以及其他复杂的文法构造,使得能够解析更复杂的语言结构。
  • 抽象语法树遍历:ANTLR4 可以生成抽象语法树,使得在解析源代码时能够更容易地进行分析和变换。AST 是编译器和解释器的核心组件。同时提供了简单的 API 来遍历生成的语法树,使得实现代码分析、转换等操作变得简单
  • 自动语法错误处理:ANTLR4 提供了内置的错误处理机制,可以在解析过程中自动处理语法错误,并且可以自定义错误消息和处理逻辑
  • 可扩展性:ANTLR4 允许用户扩展和自定义生成的解析器的行为。例如,您可以自定义解析器的方法、错误处理以及其他功能。
  • 工具&社区生态:ANTLR4 提供了丰富的工具支持,包括命令行工具、集成开发环境插件和可视化工具,可以帮助您更轻松地开发和调试解析器。同时拥有活跃的社区,提供了大量的文档、示例和支持。这使得新用户能够快速上手,并得到必要的帮助。

ANTLR4 的应用场景

Apache Spark: 流行的大数据处理框架,使用ANTLR作为其SQL解析器的一部分,支持SQL查询。
Twitter: Twitter 使用ANTLR来解析和分析用户的查询语言,这有助于他们的搜索和分析功能。
IBM: IBM使用ANTLR来支持一些其产品和工具中的DSL(领域特定语言)解析需求,例如,在其企业集成解决方案中。

ANTLR4入门

ANTLR元语言

为了实现一门计算机编程语言,我们需要构建一个程序来读取输入语句,对其中的词组和符号进行识别处理,即我们需要语法解释器或者翻译器来识别出一门特定语言的所有词组,子词组,语句。我们将语法分析过程拆分为两个独立的阶段则为词法分析和语法分析。

antlr4入门.jpeg

ANTLR语法遵循了一种专门用来描述其他语言的语法,我们称之为ANTLR元语言(ANTLR’s meta-language)。ANTLR元语句是一个强大的工具,可以用来定义编程语言的语法。通过定义词法和语法规则,可以基于antlr生成解析器和词法分析器。

1、自顶向下
在语言结构中,整体的辨识都是从最粗的粒度开始,一直进行到最详细的层次,并把它们编写成为语法规则,ANTLR4就是采用自顶向下的,词法语法分离,上下文无关的语法框架来描述语言。

// MyGLexer.g4
lexer grammar MyGLexer;

SEMICOLON: ';';
LEFT_PAREN: '(';
RIGHT_PAREN: ')';
COMMA: ',';
DOT: '.';
LEFT_BRACKET: '[';
RIGHT_BRACKET: ']';
LEFT_BRACES: '{';
RIGHT_RACES: '}';
EQ: '=';

FUNCTOM: 'FUNCTION';
LET: 'LET';
CONST: 'CONST';
VAR: 'VAR';
IF: 'IF';
ELSE: 'ELSE';
WHILE: 'WHILE';
FOR: 'FOR';
RETURN: 'RETURN';
// MyGParser.g4
parser grammar MyGParser;

options {
   
   
  tokenVocab = MyGLexer;
}

// 入口规则
program: statement* EOF;

statement:
  variableDeclaration
  | functionDeclaration
  | expressionStatement
  | blockStatement
  | ifStatement
  | whileStatement
  | forStatement
  | returnStatement;
  ......

2、语言模式

计算机语言常见4种语言模式:序列(sequence)、选择(choice)、词法符号依赖 (token dependency),以及嵌套结构(nested phrase)。以下是ANTLR对4种模式的语法规则描述。

语言模式.jpeg

3、语法歧义

在自顶向下的语法和手工编写的递归下降语法分析器中,处理表达式都是一件相当棘手的事情,这首先是因为大多数语法都存在歧义,其次是因为大多数语言的规范使用了一种特殊的递归方式,称为左递归。

expr : expr '*' expr
     | expr '+' expr
     | INT
     ;

我们举个运算符优先级带来的语法歧义问题,同样的规则可以匹配多个输入字符流

匹配多个输入字符流.jpeg

在其他语法工具中,通常通过指定额外的标记来指定运算符优先级。而在ANTLR4中通过备选分支的排序来指定优先级,越靠前优先级越高。

代码自动生成

ANTLR可以根据lexer.g4和parser.g4自动生成词法分析器,语法分析器,监听器,访问器等。

antlr4ng -Dlanguage=TypeScript -visitor -listener -Xexact-output-dir -o ./src/lib ./src/grammar/*.g

代码自动生成.jpeg

语法解析与业务逻辑解耦

在ANTLR4中语法解析和业务逻辑的高度解耦是一个重要的设计理念,优点就是同一个 AST 结构能够在不同的业务逻辑实现之间实现复用。不同的业务逻辑(如执行、转换、优化等)可以对同一个 AST 进行不同的处理,而不需要关心解析过程。核心几个设计方案如下:

  • 访问者模式:ANTLR4通过访问者模式支持业务代码可访问特定“词法”或“语法”节点执行自定义的操作,通过这个方式完全解耦AST(抽象语法树)生成和业务逻辑,词法分析器和解释器专注于AST生成,而业务可以通过访问器的扩展支持业务定制化诉求。
  • 语法和语义的独立性:ANTLR4中可以独立进行语法解析和语义分析,可以在 AST 中进行语义检查和业务逻辑处理。这种分离使得开发者可以更灵活地处理输入的语法和语义。
  • AST生成:ANRL4通过语法解析器生成结构化AST(抽象语法树),不同业务逻辑可以不断复用同一个AST。
  • 上下文模式:解析器在处理输入数据时,上下文会在解析树中传递信息。每当进入一个新的语法规则时,都会创建一个新的上下文实例上下文可以存储解析过程中需要的临时信息,例如变量的值、数据类型等。上下文信息主要结合访问器模式进行使用,同时也解决了在解析复杂语句如多层嵌套结构的层级调用问题。

三、SparkSQL介绍

Spark SQL 是 Apache Spark 的一个模块,专门用于处理结构化数据,Spark SQL 的特点包括:

  1. 高效的查询执行:通过 Catalyst 优化器和 Tungsten 执行引擎,Spark SQL 能够优化查询执行计划,提升查询性能。
  2. 与 Hive 的兼容性:Spark SQL 支持 HiveQL 语法,使得用户可以轻松迁移现有的 Hive 查询。
  3. 支持多种数据源:Spark SQL 可以从多种数据源读取数据,包括 HDFS、Parquet、ORC、JDBC 等。

四、技术实现

语法设计

在Aparch Spark源码中就是使用ANTLR4来解析和处理SQL语句,以下为Apach Spark中基于ANTLR元语言定义的词法分析器和语法分析器,在语法定义上我们只需要基于这套标准的SparkSQL语法适配得物自研引擎的能力,做能力对齐。

Lexer.g4

https://github.com/apache/spark/blob/master/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseLexer.g4

Parser.g4

https://github.com/apache/spark/blob/master/sql/api/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4

语法补全

以下我们以字段补全场景为例解析从语法定义,语法解析,语法补全,上下文信息采集各个流程节点剖析最后完成的表字段信息精准推荐。在下列语法场景中,存在多层Select语法嵌套,同时表du_emr_test.empsalary tableB和表du_emr_test.hujh_type_tk AS tableB设置了同一别名, 如图在父子查询中都使用了同一个表别名(tableB),当用户在父子查询中分别输入**tableB.**时,这时候需要结合当前上下文语境,对tableB别名推荐不同表的字段

SELECT 
    tableB.c1
 FROM
    (
       SELECT
            tableB.empno,
            tableC.department
        FROM
                du_emr_test.empsalary as tableB
        LEFT JOIN du_emr_test.employees AS tableC
        WHERE tableC.department = tableB.depname

    ) AS tableA
LEFT JOIN du_emr_test.hujh_type_tk AS tableB
WHERE tableB.c1 = tableA.dename

语法补全1.jpeg
语法补全2.jpeg

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值