精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

基于ANTLR4的大數據SQL編輯器解析引擎實踐

數據庫 其他數據庫
通過SQL引擎能力建設我們在Galaxy數據研發IDE上支持了個性化詞法規則定制能力,包含字段別名支持中文, 表變量等場景, 同時通過語法解析和監聽器能力,支持實時識別各類的語法規則,包含表,函數,字段等做輔助編程提示和做精準化的庫,表,字段代碼補全和推薦。

一、背景

二、ANTLR4 簡介

    1. ANTLR4 特性

    2. ANTLR4 的應用場景

    3. ANTLR4入門

三、SparkSQL介紹

四、技術實現

    1. 語法設計

    2. 語法補全

    3. 語法校驗

    4. 性能

    5.編輯器應用

五、大模型下的SQL編輯器應用

    1. NL2SQL應用場景

    2. NL2SQL自動補全

六、總結

一、背景

隨著得物離線業務的快速增長,為了脫離全托管服務的一些限制和享受技術發展帶來的成本優化,公司提出了大數據Galaxy開源演進項目,將離線業務從全托管且封閉的環境遷移到一個開源且自主可控的生態系統中,而離線開發治理套件是Galaxy自研體系中一個核心的項目,在數據開發IDE中最核心的就是SQL編輯器,我們需要一個SQL解析引擎在SQL編輯提供適配得物自研Spark引擎的語法定義,實時語法解析,語法補全,語法校驗等能力,結合業內dataworks和dataphin的實踐,我們最終選用ANTLR作為SQL解析引擎底座。

二、ANTLR4 簡介

ANTLR(一種語法解析引擎工具)是一個功能強大的解析器生成器,用于讀取、處理、執行或翻譯結構化文本或二進制文件。它廣泛用于構建語言、工具和框架。ANTLR可以根據語法規則文件生成一個可以構建和遍歷解析樹的解析器。

ANTLR4 特性

ANTLR4 是一個強大的工具,適合用于語言處理、編譯器構建、代碼分析等多種場景。它的易用性、靈活性和強大的特性使得它成為開發者的熱門選擇。

  1. 強大的文法定義:ANTLR4 允許用戶使用簡單且易讀的文法語法來定義語言的結構。這使得創建和維護語言解析器變得更加直觀,同時在復雜文法構造上支持左遞歸文法、嵌套結構以及其他復雜的文法構造,使得能夠解析更復雜的語言結構。
  2. 抽象語法樹遍歷:ANTLR4 可以生成抽象語法樹,使得在解析源代碼時能夠更容易地進行分析和變換。AST 是編譯器和解釋器的核心組件。同時提供了簡單的 API 來遍歷生成的語法樹,使得實現代碼分析、轉換等操作變得簡單
  3. 自動語法錯誤處理:ANTLR4 提供了內置的錯誤處理機制,可以在解析過程中自動處理語法錯誤,并且可以自定義錯誤消息和處理邏輯
  4. 可擴展性:ANTLR4 允許用戶擴展和自定義生成的解析器的行為。例如,您可以自定義解析器的方法、錯誤處理以及其他功能。
  5. 工具&社區生態:ANTLR4 提供了豐富的工具支持,包括命令行工具、集成開發環境插件和可視化工具,可以幫助您更輕松地開發和調試解析器。同時擁有活躍的社區,提供了大量的文檔、示例和支持。這使得新用戶能夠快速上手,并得到必要的幫助。

 ANTLR4 的應用場景

Apache Spark:  流行的大數據處理框架,使用ANTLR作為其SQL解析器的一部分,支持SQL查詢。

Twitter: Twitter 使用ANTLR來解析和分析用戶的查詢語言,這有助于他們的搜索和分析功能。

IBM: IBM使用ANTLR來支持一些其產品和工具中的DSL(領域特定語言)解析需求,例如,在其企業集成解決方案中。

ANTLR4入門

ANTLR元語言

為了實現一門計算機編程語言,我們需要構建一個程序來讀取輸入語句,對其中的詞組和符號進行識別處理,即我們需要語法解釋器或者翻譯器來識別出一門特定語言的所有詞組,子詞組,語句。我們將語法分析過程拆分為兩個獨立的階段則為詞法分析和語法分析。

圖片圖片

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種模式的語法規則描述。

圖片圖片

3.語法歧義

在自頂向下的語法和手工編寫的遞歸下降語法分析器中,處理表達式都是一件相當棘手的事情,這首先是因為大多數語法都存在歧義,其次是因為大多數語言的規范使用了一種特殊的遞歸方式,稱為左遞歸。

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

我們舉個運算符優先級帶來的語法歧義問題,同樣的規則可以匹配多個輸入字符流。

圖片圖片

在其他語法工具中,通常通過指定額外的標記來指定運算符優先級。而在ANTLR4中通過備選分支的排序來指定優先級,越靠前優先級越高。

代碼自動生成

ANTLR可以根據lexer.g4和parser.g4自動生成詞法分析器,語法分析器,監聽器,訪問器等。

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

圖片圖片

語法解析與業務邏輯解耦

在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

圖片圖片

圖片圖片

圖片圖片

圖片圖片

在子查詢中我們期望推薦tableB來自du_emr_test.empsalary tableB的字段信息,而在最外層中我們期望的是du_emr_test.hujh_type_tk的字段,如上圖。

基于以上場景我們核心要解決2個問題:

問題1:當前光標應該提示哪些推薦語法類型

目前,開源方案ANTLR-C3引擎就能完美解決我們問題,用戶在編輯器實時輸入時,獲取當前光標位置,實時做語法解析,然后基于開源的ANTLR-C3引擎能力結合ANTLR 生成的AST即可獲取當前光標位置所需要的語法規則。

問題2:  獲取當前上下文信息以實現精準推薦

根據不同業務場景需要采集的上下文信息不同,基于字段推薦的場景,我們需要獲取當前光標位置處可以推薦的表信息,表別名信息,結合編輯器能力實時獲取表對應的字段信息進行字段推薦補全,而上下文信息的采集,我們可以通過ANTLR生成的監聽器來實現。

語法定義

以下我們用ANTLR元語言實現一段簡化版的SQL查詢場景的語法規則(QueryStatment),方便我們理解。

lexer grammar SqlLexer;


// 基礎詞法
COMMA: ',';
LEFT_PAREN: '(';
RIGHT_PAREN: ')';
IDENTIFY: (LETTER | DIGIT | '_' | '.')+;
fragment DIGIT: [0-9];
fragment LETTER: [A-Z];
SEMICOLON: ';';


parser grammar SqlParser;


program: statment* EOF;


statment: queryStatment SEMICOLON?;
// 查詢語句
queryStatment:
  SELECT columnNames FROM (
    tableName
    | (LEFT_PAREN queryStatment LEFT_PAREN)
  ) whereExpression? relationsExpresssion? SEMICOLON?;


// 字段
columnNames: columnName (COMMA columnName)*;


tableName: IDENTIFY AS? tableAlis;


tableAlis: IDENTIFY;


columnName: IDENTIFY AS? columnAlis;


columnAlis: IDENTIFY;


whereExpression: WHERE booleanExpression;


booleanExpression: (NOT | BANG) booleanExpression           # logicalBinary
  | left = booleanExpression operator = AND right = booleanExpression # logicalBinary
  | left = booleanExpression operator = OR right = booleanExpression  # logicalBinary;


relationsExpresssion:
  LEFT JOIN tableName whereExpression?
  | RIGHT JOIN tableName whereExpression?;

代碼生成

圖片圖片

圖片圖片

以下是部分生成代碼:

1.詞法分析器

// SqlLexer.ts
    
    public static readonly COMMA = 1;
    public static readonly LEFT_PAREN = 2;
    public static readonly RIGHT_PAREN = 3;
    public static readonly IDENTIFY = 4;
    public static readonly SEMICOLON = 5;


    // 詞法分析器可以使用的通道
    public static readonly channelNames = [
        "DEFAULT_TOKEN_CHANNEL", "HIDDEN"
    ];
    // 包含了所有字面量記號的名稱
    public static readonly literalNames = [
        null, "','", "'('", "')'", null, "';'"
    ];
    // 包含為每個記號分配的符號名,這些符號在生成解析器時用于標識記號
    public static readonly symbolicNames = [
        null, "COMMA", "LEFT_PAREN", "RIGHT_PAREN", "IDENTIFY", "SEMICOLON"
    ];
    
    //  ANTLR 生成的類中的一個字段,列出了所有定義的規則
    public static readonly ruleNames = [
        "COMMA", "LEFT_PAREN", "RIGHT_PAREN", "IDENTIFY", "DIGIT", "LETTER", 
        "SEMICOLON",
    ];

2.語法分析器

ANTLR自動為每個規則生成了一個解析方法,以下是tableName的 ANTLR 中的解析器方法,具備了處理標識符、可選的別名和錯誤處理的能力。

// SQLParse.ts
// ANTLR自動生成了一個解析 SQL 表名的 ANTLR 中的解析器方法,具備了處理標識符、可選的別名和錯誤處理的能力
public tableName(): TableNameContext {
        let localContext = new TableNameContext(this.context, this.state);
        this.enterRule(localContext, 8, SqlParser.RULE_tableName);
        let _la: number;
        try {
            this.enterOuterAlt(localContext, 1);
            {
            this.state = 60;
            this.match(SqlParser.IDENTIFY);
            this.state = 62;
            this.errorHandler.sync(this);
            _la = this.tokenStream.LA(1);
            if (_la === 8) {
                {
                this.state = 61;
                this.match(SqlParser.AS);
                }
            }


            this.state = 64;
            this.tableAlis();
            }
        }
        catch (re) {
            if (re instanceof antlr.RecognitionException) {
                this.errorHandler.reportError(this, re);
                this.errorHandler.recover(this, re);
            } else {
                throw re;
            }
        }
        finally {
            this.exitRule();
        }
        return localContext;
    }

自動補全

ANTLR4代碼補全核心(antlr4-c3) 是一個開創性的工具,它為ANTLR4生成的解析器提供了一個通用的代碼補全解決方案。無論你的項目是處理哪種編程語言或領域特定語言(DSL),只要是基于ANTLR就能夠利用這個庫實現精準的代碼建議和自動補全,極大地增強開發體驗。通過antlr4-c3 能力我們通過手動配置需要收集的語法規則,獲取在當前光標處需要推薦的語法規則類型。

1.語法規則

通過ANTLR4工具我們可以自動生成Sqllexer.ts詞法解析器,SqlParser.ts語法解析器,SqlParserLister.ts訪問器,SqlParseVisitor.ts監聽器,在SqlParser 語法解析器自動生成了我們在語法定義中的語法規則。

preferredRules = new Set([
        SqlParser.RULE_tableName,
        SqlParser.RULE_columnName,
]);

2.代碼補全

以下我們實現一套簡化版的代碼補全能力。

當用戶在編輯器實時輸入時,調用getSuggestionAtCaretPosition獲取當前語境中需要推薦的信息,包含語法規則,關鍵詞,上下文信息,在結合業務層數據做自動補全,其中包含5個核心步驟:

  • 獲取當前語法解析器實例。
  • 獲取當前光標位置對應的Token。
  • 生成AST。
  • 獲取當前語境上下文信息。
  • 通過ANTLR-C3獲取當前位置候選語法規則。
public getSuggestionAtCaretPosition(
        sqlContent: string,
        caretPosition: CaretPosition
        preferredRules: Set
    ): Suggestions | null {
        
        // 1、 使用SqlParse解析器獲取
        const sqlParserIns = new SqlParse(sqlContent)
        
        // 2、獲取當前光標處token
        const charStreams = CharStreams.fromString(sqlContent);
        const lexer = new SqlLexer(charStreams);
        const tokenStream = new CommonTokenStream(lexer);
        tokenStream.fill()
        const allTokens = tokenStream.getTokens(); 
        let caretTokenIndex = findCaretToken(caretPosition, allTokens); 


        // 3、獲取AST抽象語法樹
        const parseTree = sqlParserIns.program()
        
        // 4、通過監聽器采集上下文表信息(下面上下文分析部分闡述細節)
        const tableEntity = getTableEntitys()
        
         // 異常場景兼容存在多條sql, 獲取有效最小SQL范圍給到antlr4-c3做推薦。
        const statementCount = splitListener.statementsContext?.length;
        const statementsContext = splitListener.statementsContext; 


        // 5、antlr4-c3接入獲取推薦語法規則
        let tokenIndexOffset: number = 0;
        const core = new CodeCompletionCore(sqlParserIns);
        // 推薦規則 來自SQLparse解析器的規則(元語言定義)
        core.preferredRules = preferredRules; 
        // 通過AST和當前光標Token獲取推薦類型
        const candidates = core.collectCandidates(caretTokenIndex, parseTree); 
        
        // ruleType -> preferredRules 
        // const [rules, tokens] = candidate;
        const rules = [];
        const keywords = [
                
        for (let candidate of candidates.rules) {
        const [ruleType] = candidate;
        let synContextType;
        switch (ruleType) {
            case SqlParser.RULE_tableName: {
                syntaxContextType = 'table';
                break;
            }
            case SqlParser.RULE_columnName: {
                syntaxContextType = 'column';
                break;
            }
            default:
                break;
        }
        if (synContextType) {
            rules.push(syntaxContextType)
        }
    }


    // 獲取對應keywords
    for (let candidate of candidates.tokens) {
        const displayName = sqlParserIns.vocabulary.getDisplayName(candidate[0]);
        const keyword = displayName.startsWith("'") && displayName.endsWith("'")
                ? displayName.slice(1, -1)
                : displayName
        keywords.push(keyword);
    }


    return {
        rules,
        keywords,
        tableEntity
    };
  }

在這里我們簡化了流程,忽略了很多異常case的處理,自動補全的前提是在當前語法規則正確,而在多級子查詢嵌套場景我們需要考慮到過濾異常QueryStatment,  在當前光標出最小范圍有效的QueryStatment做補全。這時候需要配合監聽器去做上下文采集做容錯性更高的自動補全。

上下文分析

圖片圖片

如圖:每個table都歸屬于一個QueryStatment表達式,  查詢中又存在子層級查詢的嵌套。我們需要通過上下文收集以下信息:

  • 每個查詢語句的信息,包含Position位置信息,記錄當前的查詢開始行,結束行,開始列,結束列。
  • 查詢語句的關聯關系,即記錄當前查詢語句父級查詢語句對象。
  • 表實體信息包含表名,表位置信息,表別名信息,當前表歸屬于那個查詢語句。

則我們需要監聽3個語法規則包含QueryStatment, TableName,TableAlias, 采集QueryStatment信息,Table信息同時將table與當前歸屬的QueryStatment做關聯, 還有與別名信息作配對關聯。這就要求在不同監聽器之間的信息需要做共享,上下文信息需要做傳遞和保留。ANTLR常用的3種信息共享方案包含:

  • 使用訪問器方法來返回值,
  • 使用類成員在事件方法之間共享數據,
  • 在語法定義中使用樹標記來存儲信息。

在這里我們使用第二種(在這里我們簡化了SQL的語法定義,在實際場景中語法層級深度和復雜度遠比當前高,這也使得方案1和3實際操作起來更麻煩,規則嵌套層級深使得方案一和方案三開發成本和維護成本更高)

1.監聽器(SqlParserLister)

通過ANTLR4工具我們可以自動生成SqlParserLister.ts監聽器進行自定義擴展。

// SqlParserListener.ts
export class QueryStatmentContext extends antlr.ParserRuleContext {
   public override enterRule(listener: SqlParserListener): void {
        if(listener.enterQueryStatment) {
             listener.enterQueryStatment(this);
        }
    }
    public override exitRule(listener: SqlParserListener): void {
        if(listener.exitQueryStatment) {
             listener.exitQueryStatment(this);
        }
    }
 }
 
 export class TableNameContext extends antlr.ParserRuleContext {
     public override enterRule(listener: SparkSqlParserListener): void {
        if(listener.enterTableName) {
             listener.enterTableName(this);
        }
    }
    public override exitRule(listener: SparkSqlParserListener): void {
        if(listener.exitTableName) {
             listener.exitTableName(this);
        }
    }
 }
// ....


export class TableAliasContext extends antlr.ParserRuleContext {
    public KW_AS(): antlr.TerminalNode | null {
        return this.getToken(SparkSqlParser.KW_AS, 0);
    }
    public override enterRule(listener: SparkSqlParserListener): void {
        if(listener.enterTableAlias) {
             listener.enterTableAlias(this);
        }
    }
    public override exitRule(listener: SparkSqlParserListener): void {
        if(listener.exitTableAlias) {
             listener.exitTableAlias(this);
        }
    }
}

2.自定義監聽器擴展

通過SqlParserListener我們可以自定義采集上下文信息。在

  • 監聽進入QueryStatment表達式采集當前表達式信息到_queryStmtsStack。
  • 監聽退出TableNameToken時采集當前Table信息,并關聯當前QueryStatment。
  • 監聽退出TableAliasToken時采集信息,并關聯到Table實體。
  • 監聽退出QueryStatment表達式推出_queryStmtsStack
// tableEntityCollect
 export class SqlEntityCollector implements SqlParserListener {
     super() {
         this._tableEntitiesSet = new Set();
         this._queryStmtsStack = [];
         this._tableAliasStack = [];
         this._currentTable = '';
     }
     
     enterQueryStatment(ctx: QueryStatmentContext) {
        this.pushQueryStmt(ctx);
    }


    exitQueryStatment(ctx: QueryStatmentContext) {
        this.popQueryStmt(); 
    }


     exitTableName(ctx: TableNameContext) {
        this.pushTableEntity(ctx);
        this.setCurrentTable(ctx);
     }
     
     exitTableAlias(ctx: TableAliasContext) {
        this.pushTableEntity(ctx);
     }
     
     pushQueryStmt() {}   // 采集QueryStmt信息
     
     popQueryStmt() {}    // 推出當前QueryStmt,進入下個同級Stmt
     
     pushTableEntity() {} // 采集當前表信息,關聯當前Stmt
     
     pushTableEntity() {} // 采集關聯表
     
     enterProgram() {}    // 清空重置
     
     getTableEntity() {
         return this.TableEntity(ctx)
     }
    
 }

在這里我們簡化了語法定義的規則便于講解,但在實際中語法規則的整體嵌套層級是很深的,從以下的SparkSql語法定義中我們可以看到右側聚合的表達式高達200+個,單個表達式的備選分支最多高達140+,這也加大了上下文分析采集的復雜度,即我們無法簡單的從QueryStmt當前QueryStatmentContext中獲取全量信息。

圖片圖片

3.觸發監聽器采集上下文信息
getTableEntitys() {
    const collectListener = new SqlEntityCollector(sqlContent, caretTokenIndex);
    const parse = new SqlParse(sqlContent);
    const parseTree= sqlParserIns.program();
    ParseTreeWalker.DEFAULT.walk(collectListener, parseTree); 
    return collectListener.getTableEntity()
}

語法校驗

ANRLR在生成語法分析器中內置了自動錯誤報告和恢復策略,能夠在遇到句法錯誤時自動產生錯誤消息,為每個句法錯誤產生一條錯誤消息。

詞法錯誤

常見的詞法錯誤包含字符遺漏,詞法錯誤。舉個例子,在spark標準語法定義中 tableName規則不支持表變量場景(${variable}),如果要兼容這里詞法,就需要在語法定義中變更tableName的語法規則定義。

圖片

以下是語法定義變更:

  • 新增詞法規則$, {, }。
  • 新增語法規則identifyVar支持變量模式。
SqlLexer.g4
// 新增詞法
LEFT_BRACE    : '{';
RIGHT_BRACE   : '}';


VARIABLE    : '$';


SqlParse.g4
// before tableName: IDENTIFY AS? tableAlis; 
tableName: identifyVar AS? tableAlis; 


identifyVar
    : IDENTIFY // odps_table_a
    | IDENTIFY? VARIABLE LEFT_BRACE IDENTIFY RIGHT_BRACE IDENTIFY? // odps_table_a_${variable} odps_table_a_${prefix_variable}_abs

自動恢復機制

語法分析器不應該在遇到非法的成員定義時結束,而是應盡最大可能匹配到一個合法的類定義,ANRTL4自動錯誤恢復機制能在語法分析器在發現語法錯誤后還能繼續進行嘗試語法解析和自動恢復。

1.異常捕獲

ANRLT自動生成的語法解析器中自動為每個規則包裹異常捕獲能力,并在catch中嘗試錯誤恢復。

圖片圖片

2.恢復策略

一般情況下,語法分析器在遇到無法匹配的錯誤時會嘗試最簡單的符號補全和移除來嘗試解析,都不管用時,這時候就會用更高階的策略來進行恢復。包括掃描后續詞法符號來恢復,從不匹配的詞法符號中恢復,從子規則的錯誤中恢復,捕獲失敗的語義判定。

雖然ANTLR提供了很多策略來進行錯誤恢復,但在實際業務場景中,需要結合考慮語法、語境的復雜度去權衡性能與更友好的錯誤提示之間的抉擇。在復雜場景中ANTLR表現并不理想,在一些復雜語法和語境的情況下解析器在檢測錯誤時難以做出合理的決策,例如:遞歸和嵌套結構中會使得錯誤恢復變得很復雜,導致解析器無法做出合理決策。還有在上下文敏感的語境中,錯誤恢復機制基本無法提供有效恢復。

性能

在 ANTLR 4 中,語法復雜度、語法歧義、語法規則嵌套深度與預測算法的選擇都會顯著影響解析器的性能和準確性。Spark SQL語法規則達200+,備選分支最高達140, 嵌套深度達20+,同時又存在負責循環嵌套場景, 這也意味著在整個語法解析,語法錯誤的處理過程是很復雜的,當遇到復雜大SQL量和一片狼籍的語法錯誤SQL,會導致語法解析過程變得緩慢引發性能問題。目前在性能優化上,有以下幾個方向。

緩存優化

在antlr4中詞法解析和語法解析能力和業務是完全解耦的,這也意味著底層基于同個SQL內容解析出來的tokens和parserTree都是可以在不同業務邏輯應用里復用。我們可以通過緩存tokens,parseTree減少詞法解析和語法解析的損耗。

語法優化

通過減少語法樹的層級和優化表達式減少解析過程中“二義性”的次數,可以加速語法解析的速度,優化AST生成性能。合理使用語法定義中用法,例如樹標記(用于上下文通信數據共享),在語法解析過程中會為每個標記生成上下文,這也意味著每個局部結果都會保留,會有更大的內存消耗。

預測模型選擇

在語法解析中不同預測模型的選擇對解析性能有顯著影響,針對不同的場景需要評估時效性與正確性之間的衡量。

ANTLR4預測模型:

https://www.antlr.org/api/Java/org/antlr/v4/runtime/atn/PredictionMode.html

圖片

我們可以選擇性價比更高的SLL預測模型作為語法分析策略,結合定制化的錯誤監聽器做錯誤糾正。

編輯器應用

編輯器集成

與MonacoEditor集成流程可查看此文章 https://blog.shizhuang-inc.com/article/MTUzNzY?fromType=personal_blog

輔助編程

1.信息項提示(表,函數,字段)

圖片圖片

圖片圖片

圖片圖片

2.自動補全(庫,表,字段,語法)

圖片圖片

圖片圖片

圖片圖片

五、大模型下的SQL編輯器應用

隨著大模型的蓬勃發展,在數據產品中的應用也逐步得到了驗證和落地,目前,Galaxy還沒有接入Copilot, 內部暫時還沒有基于SQL的Copilot。業界較成熟的是阿里云的Dataworks, DataWorks于2023年推出了Copilot 產品, 核心2個方向,一個方向是智能 SQL 編程助手,輔助 SQL 編程,支持 NL2SQL 及 SQL 代碼補全;另一個方向是 AI Agent,提供 LUI(自然語言用戶界面),以提升產品功能操作的便捷性和用戶體驗。

NL2SQL應用場景

基于SQL的Copilot一般在以下幾個應用場景比較深入和廣泛的落地效果:簡單數據查詢,SQL 優化與轉換,SQL 語法查詢與講解, 函數查詢,功能咨詢,注釋生成,SQL 解釋,SQL 一鍵糾錯。

NL2SQL自動補全

代碼補全是編程類 Copilot 的主要場景和能力,單市場上主流的編程類 Copilot 對 SQL 支持的好的并不多見。眾所周知,SQL 代碼補全比其他高級語言的代碼補全更具挑戰性,主要原因有以下幾個方面:

  • 上下文和環境的依賴性:SQL 代碼不是獨立存在的,而是依賴于數據表的元數據信息以及表與表之間的關聯關系。
  • SQL 語義多樣性:實現同一種查詢結果,可以有多種 SQL 寫法,如何實現“最佳”寫法存在挑戰。
  • 語法簡潔但高度專業化:SQL 語法簡潔但每一個關鍵字、函數或語法都有特定的含義,大模型要準確理解這些得通過針對性的訓練學習。
  • 執行計劃和性能考量: 這跟數據庫底層的執行計劃有關,需要考慮如何書寫才能使 SQL 的性能最優。
  • 數據庫特異性:市面上不同的數據庫往往存在不同的 SQL 方言,存在差異,針對這種差異性我們要投入大量時間做 SQL 數據集準備、數據標注、模型微調。
  • 高度業務相關性:SQL 語句通常與特定業務高度相關,比如一個指標存在特定的計算口徑,這是與公司業務相關,通用的大模型也無法提前學習。

目前較成熟的代碼補全核心場景主要在有規律的代碼連續推薦場景(例如:字段、字段別名推薦,注釋推薦、分區字段推薦、Group by 字段推薦,上下文自動聯想推薦等)。

六、總結

通過SQL引擎能力建設我們在Galaxy數據研發IDE上支持了個性化詞法規則定制能力,包含字段別名支持中文, 表變量等場景, 同時通過語法解析和監聽器能力,支持實時識別各類的語法規則,包含表,函數,字段等做輔助編程提示和做精準化的庫,表,字段代碼補全和推薦。

后續我們仍面臨很大的挑戰,在非專業的數據開發背景、復雜的業務定制需求、語言定義的復雜性和嵌套深度等因素共同導致了解析器的開發難度。目前,在語法校驗自動糾錯提示上,雖然ANTLR的提供了自動錯誤恢復機制但整體表現并不理想,后續2個方向,第一,接入大模型的能力。第二,從基礎語法定義上進行重構,減少語法歧義和層級優化。為了應對這些挑戰,我們需要加強對 ANTLR 和 Spark SQL語言,數據處理的理解,以便順利使用和擴展解析器。

參考資料

  • ANTLR
  • ANTLR4-C3
  • DataWorks Copilot:大模型時代數據開發的新范式
  • ANTLR4權威指南 - [美] 特恩斯·帕爾 著
責任編輯:武曉燕 來源: 得物技術
相關推薦

2016-09-23 20:30:54

Javascriptuiwebview富文本編輯器

2021-09-23 19:31:00

AI

2022-10-27 10:06:16

Presto SQLAntlr大數據

2013-06-18 01:22:46

CocoStudio工Cocos2d-x

2011-01-10 16:17:49

2021-09-23 19:30:02

AI

2010-02-23 15:29:43

Python 編輯器

2010-03-24 09:20:07

CentOS vi編輯

2023-08-31 11:32:57

圖形編輯器contain

2024-11-27 09:02:01

文本編輯canvas圖形編輯器

2011-03-22 13:54:57

UbuntuPHP編輯器

2011-01-19 13:40:33

htmlcsswindows

2015-04-22 13:20:21

企業網D1Net

2017-03-09 11:45:16

LinuxVim編輯器

2025-02-05 12:01:35

屬性編輯器Web

2019-07-10 13:17:07

大數據搜索代碼

2017-04-21 11:24:13

數據庫Azure T-SQL編輯器

2018-09-25 09:25:11

Vim編輯器命令

2022-12-23 09:29:52

大數據

2025-08-19 02:33:00

點贊
收藏

51CTO技術棧公眾號

在线观看成人黄色| 成人免费在线视频| 国产成人精品亚洲精品| 九九这里只有精品视频| 国产66精品| 在线看不卡av| 欧美精品久久久久久久久久久| 国产精品一区二区婷婷| 国产福利91精品一区| 国产成人av网址| 免费在线观看国产精品| 精品久久久亚洲| 亚洲第一免费播放区| 国产成人黄色网址| 日韩伦理在线| 亚洲一区影音先锋| 亚洲精品日韩在线观看| 亚欧在线观看视频| 国产精品香蕉一区二区三区| 国产精品第2页| 日本系列第一页| 亚洲成人精选| 中文字幕免费精品一区| av在线网站观看| 99a精品视频在线观看| 欧美日韩国产免费一区二区| 天天摸天天碰天天添| 国产天堂在线播放视频| 日韩美女啊v在线免费观看| 欧美日韩国产精品一卡| 日本成人动漫在线观看| 国产精品99久久久久| 成人福利在线视频| 日韩av免费播放| 亚洲综合欧美| 91精品国产91久久久久福利| 国产在线观看成人| 欧美一区亚洲| 理论片在线不卡免费观看| 亚洲色图 激情小说| 精品国产91乱码一区二区三区四区 | 国产成人精品www牛牛影视| 国产精品精品久久久久久| 欧美精品二区三区| 国产亚洲网站| 日本中文字幕久久看| 色屁屁影院www国产高清麻豆| 亚洲看片免费| 4p变态网欧美系列| 欧美一级片免费在线观看| 亚洲少妇自拍| 欧美在线性爱视频| 欧美精品一二三四区| 久久99伊人| 国产成人久久久| 亚洲精品无码久久久久| 奇米综合一区二区三区精品视频| 国产精品入口免费视| 中文字幕一区二区人妻| 麻豆久久一区二区| 91在线观看欧美日韩| japanese国产| 国产视频精品久久久| 一区二区三区四区久久| jizz亚洲| 亚洲日本一区二区| 在线观看18视频网站| 在线观看中文字幕的网站| 亚洲日本欧美天堂| 国产九色porny| 玖玖在线播放| 欧日韩精品视频| 日韩成人av免费| 亚洲电影一区| 日韩理论片久久| 黄色片网站免费| 国产精品成久久久久| 美女黄色丝袜一区| 亚州国产精品视频| 丝袜美腿一区二区三区| 成人在线观看视频网站| 蜜桃久久一区二区三区| 久久在线观看免费| 亚洲精品无人区| 国产第一页在线| 色综合久久精品| 亚洲18在线看污www麻豆| 中文字幕一区二区三区日韩精品| 精品偷拍一区二区三区在线看 | 国产精品国产av| 国产**成人网毛片九色| 日韩精品在在线一区二区中文| 精品国产99久久久久久| 福利微拍一区二区| 午夜视频在线网站| 欧洲亚洲一区二区三区| 日韩一区二区久久久| 日本道在线观看| 久久99热狠狠色一区二区| 国产一区免费观看| 毛片在线视频| 色女孩综合影院| 乱码一区二区三区| 秋霞欧美视频| 17婷婷久久www| 性欧美videos另类hd| 国产婷婷色一区二区三区在线| www.69av| 亚洲香蕉久久| 国产一区二区三区视频在线观看| 国产精品2020| 国产原创一区二区三区| 性刺激综合网| 亚洲色图官网| 欧美不卡一区二区| 手机av在线看| 日本女优在线视频一区二区 | heyzo久久| 欧美在线不卡区| 亚洲老妇色熟女老太| 中文字幕在线不卡国产视频| 国产一区视频免费观看| 成人h动漫免费观看网站| 久久亚洲精品视频| 亚洲视频在线观看免费视频| 久久免费的精品国产v∧| 亚洲 欧美 综合 另类 中字| 91麻豆精品一二三区在线| 国产午夜精品免费一区二区三区 | 日本三级一区| 欧美精品一区二区三区一线天视频| 波多野结衣家庭教师| 久久国产人妖系列| 亚洲看片网站| 精品女同一区二区三区在线观看| 亚洲视频在线视频| 亚洲毛片一区二区三区| 91日韩一区二区三区| 国产在线播放观看| 荡女精品导航| 午夜精品久久久久久久白皮肤| 成人久久久精品国产乱码一区二区 | 久久中文字幕在线观看| 国产精品99久久久久久久vr| 亚洲高潮无码久久| 免费一区二区三区在线视频| 免费不卡欧美自拍视频| 国产xxxx孕妇| 亚洲图片欧美视频| xxxx黄色片| 国产日韩亚洲| 欧美日韩一区综合| 日韩免费小视频| 日韩小视频在线观看| 97视频免费在线| 亚洲女人的天堂| 日韩av成人网| 一本久道综合久久精品| 看高清中日韩色视频| 性欧美1819sex性高清| 亚洲图中文字幕| 在线观看国产精品入口男同| 亚洲精品乱码久久久久久黑人 | 亚洲黄色尤物视频| 欧美性生交xxxxx| 羞羞答答国产精品www一本 | 精品99视频| 精品一区二区三区自拍图片区| 欧美成人h版| 精品国产一区久久久| 99久久精品免费看国产交换| 亚洲国产精品一区二区久久| 久久亚洲AV无码专区成人国产| 麻豆成人av在线| 国产肉体ⅹxxx137大胆| 性欧美lx╳lx╳| 国产视频福利一区| 岛国毛片av在线| 夜夜嗨av一区二区三区四区| 国产精品一区二区av白丝下载| 亚瑟在线精品视频| 国产精品1区2区3区4区| 粉嫩一区二区三区在线看| 六月丁香婷婷在线| 亚洲成av人电影| 蜜桃网站成人| 久久爱www.| 日本欧美中文字幕| 成人在线观看免费网站| 精品亚洲一区二区三区在线播放 | 亚洲大尺度在线观看| 玉足女爽爽91| 成人无码av片在线观看| 国产成人高清在线| 99视频在线视频| 亚洲精品孕妇| 91xxx视频| 国产精品一国产精品| 91手机在线观看| 国产69精品久久久久9999人| 国产+人+亚洲| 免费大片在线观看www| 精品小视频在线| 午夜精品久久久久久久99老熟妇| 在线观看免费亚洲| 国产情侣在线视频| 亚洲免费伊人电影| 国产探花视频在线播放| 91在线国产观看| 精品人妻二区中文字幕| 捆绑调教一区二区三区| 成年人网站大全| 夜夜爽av福利精品导航| 中文字幕色呦呦| 欧美电影免费| 日本一区二区三区视频免费看| 免费日韩一区二区三区| 国产91亚洲精品一区二区三区| 欧美一级在线| 国产精品网站大全| 国产亚洲一区二区手机在线观看| 91精品国产高清久久久久久91| 亚洲性图自拍| 久久亚洲精品中文字幕冲田杏梨| 国产免费av高清在线| 亚洲精品视频免费| 日本精品专区| 亚洲另类图片色| 污污的视频网站在线观看| 日韩欧美一区二区在线视频| 99在线无码精品入口| 欧美精品1区2区3区| 亚洲天堂男人网| 欧美日韩免费高清一区色橹橹| 免费无码国产精品| 色婷婷av一区二区三区之一色屋| 天堂网一区二区三区| 午夜精品一区二区三区三上悠亚| 久久综合加勒比| 亚洲国产综合色| 国产系列精品av| 午夜精品一区在线观看| 欧美videossex极品| 欧美性20hd另类| 老熟妇仑乱一区二区av| 在线一区二区三区四区五区| 欧美一级淫片免费视频黄| 一区视频免费观看| 国产精品美女| 欧美亚洲另类色图| 这里只有精品在线| 99九九视频| 青草伊人久久| 成人在线观看91| 精品麻豆剧传媒av国产九九九| 亚洲a区在线视频| 深夜福利一区| 国产综合欧美在线看| 欧美美女黄色| 日本精品视频一区| 色爱综合网欧美| 警花观音坐莲激情销魂小说| 欧美三级在线| 男人日女人下面视频| 男人的天堂亚洲| 日韩中文字幕a| 国产高清精品久久久久| 在线视频 日韩| 久久久久久久精| www.99re6| 亚洲成a人在线观看| 日韩在线播放中文字幕| 欧美日韩国产首页在线观看| 草草视频在线播放| 亚洲男人天堂网| 日本暖暖在线视频| 欧美极品少妇xxxxⅹ裸体艺术 | 欧美激情综合色| 成人国产二区| 91视频国产精品| 偷拍亚洲精品| 精品少妇人妻av一区二区| 精品福利av| 亚洲精品视频导航| 国产激情偷乱视频一区二区三区 | 一区在线观看视频| 日本在线视频中文字幕| 欧美中文字幕一区| www.四虎在线观看| 亚洲视频axxx| 在线heyzo| 日本一欧美一欧美一亚洲视频| 国产精品1区在线| 欧美在线一二三区| 欧美日韩第一区| 免费看污污网站| k8久久久一区二区三区| 天海翼在线视频| 色综合久久天天综合网| www.蜜桃av.com| 在线播放亚洲激情| caoporn视频在线观看| 成人国产在线视频| 欧美美女在线| 国产精品沙发午睡系列| 国产麻豆成人传媒免费观看| 亚洲第一视频区| 欧美三级xxx| 亚洲精品国产精品国| 色哟哟亚洲精品一区二区| 手机在线理论片| 国产精品国产精品国产专区蜜臀ah | av网站手机在线观看| 精品一区二区在线观看| 精品国产无码在线观看| 午夜久久久久久久久| www视频在线| 精品国产欧美成人夜夜嗨| 日韩电影免费观| 久久99精品久久久久久久青青日本| 欧美国产三区| 三级av免费看| 日韩一区在线免费观看| 中文字幕在线观看视频一区| 亚洲人成电影网| jk漫画禁漫成人入口| 精品乱子伦一区二区三区| 欧美午夜影院| 日本黄色一级网站| 亚洲欧美另类久久久精品| 7777久久亚洲中文字幕| 最近2019中文字幕mv免费看| 国产一区二区三区影视| 亚洲高清视频一区二区| 日韩成人dvd| 老熟妇一区二区| 91福利视频在线| 成人不用播放器| 国产在线播放91| 国产精品久久久久久久免费观看| 最新免费av网址| 亚洲男人的天堂av| 国产不卡精品视频| 欧美国产日韩一区二区三区| 2020最新国产精品| 欧美精品久久久久久久自慰| av电影在线观看一区| 国产成人精品网| 一区二区三区黄色| 色综合久久久| 超级碰在线观看| 99免费精品在线| 五月天婷婷久久| 一本久久综合亚洲鲁鲁| 日韩三区四区| 男人添女荫道口喷水视频| 99久久国产综合精品女不卡| 黄色在线免费观看| 中文字幕日韩高清| 成人av在线播放| 91专区在线观看| 国产欧美日韩精品在线| 国产绿帽一区二区三区| 国外成人免费在线播放| 亚洲小说图片| 亚洲怡红院在线| 亚洲国产一区二区在线播放| 免费av在线电影| 91在线免费观看网站| 99国产精品| 91av手机在线| 精品va天堂亚洲国产| 少妇一区视频| 亚洲一区 在线播放| 91美女在线视频| 91国偷自产中文字幕久久| 国语自产精品视频在免费| 国产一区二区精品久| 99中文字幕在线| 疯狂做受xxxx高潮欧美日本| 日本电影全部在线观看网站视频| 国产精品白丝jk白祙| 三级亚洲高清视频| 日本天堂中文字幕| 亚洲欧洲免费视频| 亚洲一区二区三区中文字幕在线观看| 1024精品视频| 亚洲日本乱码在线观看| 欧美一区二区少妇| 亚洲最大成人在线| 久久综合图片| 免费一级片视频| 最好看的2019年中文视频| 动漫视频在线一区| 中文字幕 日韩 欧美| 欧美日韩在线看| 手机在线免费av| 艳色歌舞团一区二区三区| 99久久综合精品| av免费观看在线|