SparkSQL-执行流程

一、示例代码

我们从一句常用的sql开始分析

import spark.implicits._
import spark.sql

sql("SELECT * FROM ods.personal_info limit 10").show()

其中包含两个函数调用,sql()和show(),我们依次来分析下

二、sql()

1、SparkSession

它是使用Dataset和DataFrame API对Spark编程的入口点

  //使用Spark执行SQL查询,将结果作为“DataFrame”返回。
  def sql(sqlText: String): DataFrame = {
    Dataset.ofRows(self, sessionState.sqlParser.parsePlan(sqlText))
  }

这里要分析来两处:

        1、sessionState.sqlParser.parsePlan(sqlText)

        2、Dataset.ofRows()

我们先看下第1处,它是通过ParserInterface调用其子类AbstractSqlParser来实现

2、AbstractSqlParser

  //为给定的SQL字符串创建逻辑计划
  override def parsePlan(sqlText: String): LogicalPlan = parse(sqlText) { parser =>
    //获取将ParseTree转换为AST的构建器(访问者) 
    //这里用到了ANTLR的知识
    astBuilder.visitSingleStatement(parser.singleStatement()) match {
      case plan: LogicalPlan => plan
      case _ =>
        val position = Origin(None, None)
        throw QueryParsingErrors.sqlStatementUnsupportedError(sqlText, position)
    }
  }


  protected def parse[T](command: String)(toResult: SqlBaseParser => T): T = {
    logDebug(s"Parsing command: $command")

    //1、将sql转换成字符流
    //2、将字符流全部转换成大写,这大大简化了对流的词法分析,同时我们可以保持原始命令
    //3、词法分析是基于Hive的org.apache.hadoop.hive.ql.parse.ParseDriver.ANTLRNoCaseStringStream
    //4、Hive词法分析是基于ANTLR4
    val lexer = new SqlBaseLexer(new UpperCaseCharStream(CharStreams.fromString(command)))
    lexer.removeErrorListeners()
    lexer.addErrorListener(ParseErrorListener)
 
    //使用指定的令牌源和默认令牌通道 构造一个新的 CommonTokenStream
    val tokenStream = new CommonTokenStream(lexer)
    //解析
    val parser = new SqlBaseParser(tokenStream)
    parser.addParseListener(PostProcessor)
    parser.removeErrorListeners()
    parser.addErrorListener(ParseErrorListener)
    //spark.sql.legacy.setopsPrecedence.enabled  默认false
    //当设置为true并且括号未指定求值顺序时,设置操作将在查询中从左向右执行。当设置为false且括号未指定求值顺序时,INTERSECT操作将在任何UNION、EXCEPT和MINUS操作之前执行。
    parser.legacy_setops_precedence_enabled = conf.setOpsPrecedenceEnforced
    //spark.sql.legacy.exponentLiteralAsDecimal.enabled 默认值 false
    //当设置为true时,具有指数的文字(例如1E-30)将被解析为Decimal而不是Double。
    parser.legacy_exponent_literal_as_decimal_enabled = conf.exponentLiteralAsDecimalEnabled
    //spark.sql.ansi.enabled   默认 false
    //如果为true,Spark SQL将使用符合ANSI的方言,而不是符合Hive的方言。
    //
    parser.SQL_standard_keyword_behavior = conf.ansiEnabled

    try {
      try {
        // 首先,尝试使用可能更快的SLL模式进行解析
        parser.getInterpreter.setPredictionMode(Pre
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值