精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

久久久亚洲欧洲日产国码αv| 91久久午夜| 欧美日韩成人在线| 丁香六月激情网| 蜜桃视频在线免费| 精品午夜一区二区三区在线观看| 色综合天天狠天天透天天伊人| 双性尿奴穿贞c带憋尿| 涩涩涩久久久成人精品| 精品国产精品自拍| 一区二区三区国产福利| 偷拍25位美女撒尿视频在线观看| 男男视频亚洲欧美| 国模吧一区二区| 欧美自拍偷拍网| 日本亚洲不卡| 日韩精品中午字幕| 色综合色综合色综合色综合| 成人av影院在线观看| 国产精品理伦片| 牛人盗摄一区二区三区视频| 精品国产亚洲av麻豆| 亚洲欧美成人综合| 欧美激情奇米色| 国产黄色片在线| 精品一区亚洲| 亚洲国产精品悠悠久久琪琪| 在线播放黄色av| 日韩网站中文字幕| 欧美日韩一区二区在线播放| 国产日韩亚洲欧美在线| 日本综合在线| 欧美国产视频在线| 欧美日韩一区二区三| 亚洲日本中文字幕在线| 高清av一区二区| 91在线免费看网站| 一级黄色大片免费观看| 首页亚洲欧美制服丝腿| 全亚洲最色的网站在线观看| 四虎成人精品永久免费av| 911精品美国片911久久久| 中文字幕国产日韩| 久久婷婷五月综合| 久久99国产精品视频| 日韩电影网在线| 给我免费观看片在线电影的| 国产成人精品亚洲线观看| 欧美一区二区三区小说| 欧美午夜精品理论片| 久久亚洲资源中文字| 欧美在线视频全部完| 欧美黑人又粗又大又爽免费| 久久电影tv| 欧美亚洲一区二区三区四区| 宅男噜噜噜66国产免费观看| 亚洲一区二区三区四区| 色综合久久综合网97色综合| 日本女优爱爱视频| 欧洲精品一区二区三区| 欧美日韩日日摸| 热久久久久久久久| 国产精选久久| 精品国产制服丝袜高跟| 亚洲自拍偷拍精品| 日韩精品丝袜美腿| 亚洲天堂av在线免费观看| 调教驯服丰满美艳麻麻在线视频 | 日韩成人一级片| 国产91精品网站| 中文字幕av网站| 精品一区二区免费| 97超碰人人看人人| 香蕉av一区二区三区| 久久久综合激的五月天| 天天综合色天天综合色hd| 香蕉视频在线播放| 亚洲精品水蜜桃| 男人日女人逼逼| 日本少妇一区| 欧美一二三四在线| 中文在线永久免费观看| 成人综合久久| 欧美疯狂性受xxxxx另类| 日本中文字幕在线免费观看| 久久一日本道色综合久久| 国产在线精品成人一区二区三区| 国产肥老妇视频| wwww国产精品欧美| 国产日本欧美在线| 忘忧草在线日韩www影院| 欧美色图一区二区三区| 久久精品无码专区| 欧美美女在线| 欧美日韩xxxxx| 中文字幕在线欧美| 国产a级毛片一区| 欧美一区免费视频| 91高清在线观看视频| 欧美日韩综合视频网址| 亚洲综合婷婷久久| 你懂的在线观看一区二区| 中文精品99久久国产香蕉| 黄色一级视频免费观看| 丝瓜av网站精品一区二区| 97se国产在线视频| 95在线视频| 欧美日韩国产一中文字不卡| 天堂中文av在线| 日韩精品丝袜美腿| 色在人av网站天堂精品| 国产无遮挡又黄又爽又色视频| 国产精品自拍在线| 欧美性天天影院| 牛牛精品视频在线| 欧美日韩精品一区二区三区蜜桃 | 欧美激情18p| 又污又黄的网站| 久久综合一区二区| 97超碰在线人人| 精品国产亚洲一区二区三区| 亚洲性av网站| 欧美一区二区激情视频| 国产成人免费视频精品含羞草妖精 | 毛片一区二区三区四区| 91成人短视频| 欧美精品少妇videofree| 伊人网免费视频| 国产午夜亚洲精品理论片色戒| aa视频在线播放| 成人51免费| yw.139尤物在线精品视频| 激情网站在线观看| 久久综合色一综合色88| 欧美久久久久久久久久久久久| 久久国际精品| 欧美成人亚洲成人日韩成人| 一级黄色大片网站| 国产精品欧美久久久久一区二区| 欧美韩国日本在线| 美女毛片一区二区三区四区| 欧美亚洲国产日本| 午夜国产在线视频| 精品久久久久久久久久久| 国产十八熟妇av成人一区| 亚洲私拍自拍| 国产精品综合久久久久久| 国产三级伦理在线| 亚洲国产成人一区| 国产情侣自拍av| www欧美成人18+| 欧美少妇性生活视频| 国产一区二区三区日韩精品| 国产精品久久999| 成年人视频网站在线| 欧美手机在线视频| 99久久精品久久亚洲精品| 久久国产精品免费| 日韩中文字幕亚洲精品欧美| 亚洲成av人片在线观看www| 欧美激情欧美激情在线五月| 亚洲乱码在线观看| 亚洲.国产.中文慕字在线| xfplay5566色资源网站| 久久久久国产精品午夜一区| 日韩久久精品一区二区三区| 国产原创一区| 欧美人在线观看| 无码精品视频一区二区三区| 色视频欧美一区二区三区| 久久午夜精品视频| 国产在线播放一区| 日本欧美视频在线观看| 竹菊久久久久久久| 国产精品网红直播| 18在线观看的| 亚洲精品一区av在线播放| 中文字幕手机在线视频| 国产精品成人网| 俄罗斯黄色录像| 日日夜夜一区二区| 欧美另类videosbestsex日本| 老牛国内精品亚洲成av人片| 国产精品久久久久久久久久新婚| 成人日批视频| 国产视频自拍一区| 一区不卡在线观看| 午夜久久久久久电影| 国产极品视频在线观看| 国产精品一区二区在线看| 中国丰满人妻videoshd| 97精品国产福利一区二区三区| 国产精品乱子乱xxxx| 成人啊v在线| 久久露脸国产精品| 在线免费看av| 日韩成人在线电影网| 国产一区二区小视频| 天天影视网天天综合色在线播放| 日本欧美一区二区三区不卡视频 | 天堂久久精品忘忧草| 国产一区二区三区综合| 无码人妻精品一区二区三区在线| 婷婷亚洲五月| 欧美不卡三区| 波多野结衣在线一区二区| 国产精品美女主播| 蜜桃视频动漫在线播放| 久久久av一区| 成人免费在线视频网| 亚洲国产欧美日韩精品| 国产又粗又猛又爽又黄91| 日韩欧美a级成人黄色| 美女的奶胸大爽爽大片| 国产精品你懂的| 精品无人区无码乱码毛片国产| 国产精品亚洲人在线观看| 日本999视频| 亚洲欧美日本国产专区一区| 国产成人生活片| 久久一本综合| 日韩三级电影| 亚洲免费福利一区| 国内精品久久国产| 国产日韩一区二区三免费高清| 国产成人免费av电影| 性感女国产在线| 久久久久久综合网天天| 自拍亚洲图区| 久久在线免费视频| 欧美日韩在线看片| 色琪琪综合男人的天堂aⅴ视频| 九色网友自拍视频手机在线| 亚洲福利在线观看| 色wwwwww| 亚洲国产精品999| 蜜桃av中文字幕| 亚洲国产精久久久久久| 免费观看的毛片| 亚洲国产欧美一区二区丝袜黑人| 亚洲黄色小说网址| 亚洲国产成人精品电影| 天堂在线资源8| 日韩精品一区二区视频| 欧美一区二区三区黄片| 精品99一区二区| 亚洲精品久久久狠狠狠爱 | 欧美在线亚洲综合一区| av电影一区二区三区| 91国语精品自产拍| 男女激烈动态图| 国产综合婷婷| 国自产拍偷拍精品啪啪一区二区 | 亚洲在线视频免费观看| 久久亚洲成人av| 亚洲成人av电影| 久热这里只有精品6| 黑人巨大精品欧美一区二区三区 | 日韩精品视频在线免费观看| 天堂v视频永久在线播放| 亚洲码在线观看| 成年人在线观看网站| 久久综合伊人77777尤物| 欧美6一10sex性hd| 2024亚洲男人天堂| 99欧美精品| 97自拍视频| 奇米影视777在线欧美电影观看| 蜜桃欧美视频| 99国产**精品****| 国产青草视频在线观看| 99pao成人国产永久免费视频| 国产又黄又猛视频| 久久国产三级精品| 免费黄色av网址| 久久久久久久久99精品| 色哟哟一一国产精品| 亚洲高清免费视频| 中文字幕乱伦视频| 日韩美女在线视频| 国产在线超碰| 久久av红桃一区二区小说| 麻豆国产在线| 国产欧美日韩精品丝袜高跟鞋| 日韩高清在线观看一区二区| 精品一区二区三区国产| 三级电影一区| 国产91xxx| 韩国午夜理伦三级不卡影院| 亚洲中文字幕无码av| 中文字幕一区二区三区精华液| 久久精品国产亚洲AV无码麻豆| 在线观看欧美精品| 高清乱码毛片入口| 色av吧综合网| 在线毛片观看| 成人自拍偷拍| 国产精品久久久久久久久久10秀| 水蜜桃色314在线观看| 精品一区二区在线观看| 成人手机在线免费视频| 亚洲人成伊人成综合网小说| 日日骚av一区二区| 欧美成人福利视频| 91在线播放网站| 69影院欧美专区视频| 欧州一区二区三区| 亚洲精品乱码视频| 亚洲欧美bt| 日韩综合第一页| 日韩美女视频一区二区 | 欧美日韩精品综合| 欧美天天在线| 午夜激情影院在线观看| 国产女主播一区| 日本三级小视频| 欧美成人国产一区二区| 成年人黄视频在线观看| 国产精品最新在线观看| 亚洲裸色大胆大尺寸艺术写真| 国精产品一区一区三区视频| 国产成人免费视频一区| 午夜免费激情视频| 欧美日本精品一区二区三区| 国产精品视频一区二区久久| 97超碰国产精品女人人人爽| 999国产精品一区| 三级在线免费观看| 激情成人综合网| 国产3级在线观看| 欧美性受极品xxxx喷水| 国产三级在线免费| 日本国产欧美一区二区三区| 欧美日韩麻豆| 午夜精品久久久久久久无码 | 九九热久久免费视频| 一本色道久久综合亚洲91 | 国产免费不卡视频| 精品国内自产拍在线观看| 久久三级毛片| 免费观看中文字幕| 国产精品一区二区男女羞羞无遮挡| 亚洲综合图片一区| 欧美精品tushy高清| 免费人成在线观看播放视频| 国产日韩欧美91| 亚洲欧美综合久久久| 成人性生交视频免费观看| 亚洲欧美日本韩国| 国产日韩欧美视频在线观看| 美日韩精品免费视频| 伊色综合久久之综合久久| 成人在线播放网址| 不卡av在线免费观看| 亚洲伊人成人网| 在线播放国产精品| 一区二区三区| 2022中文字幕| 成人aa视频在线观看| 国产又黄又爽又色| 在线成人免费网站| 久久gogo国模啪啪裸体| 日韩欧美精品免费| 久久综合一区二区| 91福利免费视频| 欧美黑人一区二区三区| 奇米影视777在线欧美电影观看| 不要播放器的av网站| 国产精品美女久久久久久2018 | 亚洲乱码国产乱码精品精天堂| 欧美三区四区| 佐佐木明希av| 97se亚洲国产综合自在线不卡 | 亚洲精品人成| 国产成人综合在线| 国内精品福利视频| 日韩中文有码在线视频| 亚洲精品国产九九九| 四虎永久在线精品无码视频| 中文字幕一区日韩精品欧美| 亚洲国产av一区二区| 热99精品只有里视频精品| 国产精品99视频| 无码一区二区精品| 欧美日韩成人在线一区| 欧美a级在线观看| 一本一本a久久| 91香蕉视频在线| 国产精品区在线观看| 91豆花精品一区| 999国产精品999久久久久久| 成人在线电影网站| 欧美日韩www| 狠狠操一区二区三区| 永久免费在线看片视频| 91小视频在线免费看| 国产情侣激情自拍| 日韩免费av一区二区| 女人色偷偷aa久久天堂| 免费看91的网站|