Análise do código-fonte SQL do Spark (1) Visão geral do processo de catalisador da estrutura de análise SQL

O módulo Spark SQL é principalmente para lidar com algum conteúdo relacionado à análise de SQL.Em termos gerais, é como analisar uma instrução SQL em uma tarefa Dataframe ou RDD. Tomando o Spark 2.4.3 como exemplo, o grande módulo do Spark SQL é dividido em três submódulos, como mostrado abaixo

módulo sql spark

Entre eles, pode-se dizer que o Catalyst é uma estrutura dedicada à análise de SQL no Spark.Uma estrutura semelhante no Hive é o Calcite (analise o SQL nas tarefas do MapReduce). O Catalyst divide a tarefa de análise do SQL em vários estágios, o que é descrito mais claramente no artigo correspondente. Muitos conteúdos desta série também se referem ao artigo. Os interessados ​​em ler o artigo original podem ir aqui: Spark SQL: Processamento de dados relacionais no Spark .

O módulo Core é, na verdade, o principal processo de análise do Spark SQL e, é claro, algum conteúdo do Catalyst será chamado nesse processo. As classes mais usadas neste módulo incluem SparkSession, DataSet, etc.

Quanto ao módulo de seção, não é preciso dizer que ele deve estar relacionado à seção. Este módulo basicamente não está envolvido nesta série, então não vou apresentá-lo muito.

Vale ressaltar que, quando o artigo foi publicado, ele ainda estava no estágio Spark1.x.Nessa época, o SQL era analisado em uma árvore lexical usando uma ferramenta de análise escrita em scala.No estágio 2.x, o antlr4 era usado para fazer essa parte Deve ser a maior mudança). Quanto ao motivo pelo qual deve ser alterado, acho que é devido à legibilidade e facilidade de uso, é claro, esse é apenas um palpite pessoal.

Além disso, esta série apresentará brevemente o fluxo de processamento de uma instrução SQL, com base no spark 2.4.3 (o módulo sql não mudou muito após o spark2.1). Este artigo apresenta primeiro os antecedentes e a solução de problemas do Spark SQL como um todo, qual é o processo da API Dataframe e do Catalyst e, em seguida, detalha o processo do Catalyst em etapas.

Os antecedentes e os problemas do Spark SQL

Desde o início, a tecnologia para processamento de dados em larga escala era o MapReduce, mas a eficiência da implementação dessa estrutura era muito lenta e algum processamento relacional (como a junção) exigia muito código. Posteriormente, a estrutura como o hive permite que os usuários insiram instruções sql, otimizem e executem automaticamente.

No entanto, em sistemas grandes, ainda existem dois problemas principais: um é que as operações de ETL precisam interagir com várias fontes de dados. A outra é que os usuários precisam executar análises complexas, como aprendizado de máquina e cálculo de gráficos. Mas é mais difícil perceber no sistema de processamento relacional tradicional.

O Spark SQL fornece dois submódulos para resolver esse problema, API DataFrame e Catalyst .

Comparado ao RDD, o Dataframe api fornece um api relacional mais rico e pode ser convertido com RDD, e o foco do aprendizado de máquina do Spark posteriormente, também transferido do mllib baseado em RDD para o Spark ML baseado em Dataframe ( Embora a parte inferior do Dataframe também seja RDD).

O outro é o Catalyst, por meio do qual você pode facilmente adicionar fontes de dados (como json ou tipos personalizados por meio da classe case) a domínios como aprendizado de máquina e otimizar regras e tipos de dados.

Por meio desses dois módulos, o Spark SQL atinge principalmente os seguintes objetivos:

  • Forneça uma API fácil e fácil de usar, incluindo a leitura de fontes de dados externas e o processamento de dados relacionais (todos que a usaram sabem)
  • Use a tecnologia DBMS estabelecida para fornecer alto desempenho.
  • Suporte facilmente novas fontes de dados, incluindo dados semiestruturados e bancos de dados externos (como MYSQL).
  • Expansão em computação gráfica e aprendizado de máquina

Em seguida, apresente o processo do Dataframe e do Catalyst, é claro, a principal discussão é o Catalyst.

Dataframe da API unificada

Primeiro, observe uma imagem fornecida no artigo:

Quadro de dados

Essa imagem pode explicar muito, em primeiro lugar, a camada inferior da API Dataframe do Spark também é baseada no RDD do Spark. Mas a diferença com o RDD é que o Dataframe manterá o esquema (isso é realmente difícil de traduzir, pode ser entendido como a estrutura dos dados) e pode executar uma variedade de operações relacionais , como Selecionar, Filtrar, Unir, Agrupar, etc. Do ponto de vista operacional, é semelhante ao Dataframe do pandas (até o nome é o mesmo).

Ao mesmo tempo, por se basear no RDD, muitos recursos do RDD podem ser desfrutados pelo Dataframe, como consistência de computação distribuída, garantia de confiabilidade e podem armazenar dados em cache no cache para melhorar o desempenho da computação etc.

Ao mesmo tempo, a página da figura mostra que o Dataframe pode ser conectado a um banco de dados externo através do JDBC, através da operação do console (spark-shell) ou programa do usuário. Para ser franco, o Dataframe pode ser convertido por RDD ou gerado por uma tabela de dados externa .

A propósito, a propósito, muitos sapatos infantis expostos ao Spark SQL pela primeira vez podem ficar confusos sobre as duas coisas: Dataset e Dataframe.Na era 1.x, eles são realmente um pouco diferentes. Foi unificado. Então, basicamente, Dataset e Dataframe podem ser considerados equivalentes .

Por fim, vamos fazer uma exibição prática em combinação com o código: A seguir, mostra a geração de um RDD e o Dataframe correspondente é gerado de acordo com este RDD, a partir do qual você pode ver a diferença entre o RDD e o Dataframe:

//生成RDD
scala> val data = sc.parallelize(Array((1,2),(3,4)))
data: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[0] at parallelize at <console>:24

scala> data.foreach(println)
(1,2)
(3,4)

scala> val df = data.toDF("fir","sec")
df: org.apache.spark.sql.DataFrame = [fir: int, sec: int]

scala> df.show()
+---+---+
|fir|sec|
+---+---+
|  1|  2|
|  3|  4|
+---+---+

//跟RDD相比,多了schema
scala> df.printSchema()
root
 |-- fir: integer (nullable = false)
 |-- sec: integer (nullable = false)

Análise de fluxo de catalisador

O Catalyst é chamado Optimizer no artigo. Esta parte é o conteúdo principal do artigo, mas o processo é realmente fácil de entender.A imagem no artigo ainda é publicada.

processo catalisador

O processo principal pode ser dividido aproximadamente nas seguintes etapas:

  1. A instrução Sql é analisada pelo Antlr4 para gerar um Plano Lógico Não Resolvido (os sapatos de crianças que usaram o Antlr4 devem estar familiarizados com esse processo)
  2. O analisador e o catálogo são vinculados (metadados das lojas de catlog) para gerar o Plano Lógico;
  3. O otimizador otimiza o plano lógico e gera o LogicalPlan otimizado;
  4. O SparkPlan converte o LogicalPlan otimizado em plano físico;
  5. prepareForExecution () converte o Plano Físico em Plano Físico executado;
  6. execute () executa o plano físico executável e obtém o RDD;

Deixe-me falar sobre isso com antecedência.A maioria dos processos acima está na classe org.apache.spark.sql.execution.QueryExecution.Este post é um código simples, basta olhar para ele. Os artigos posteriores detalharão o conteúdo aqui.

class QueryExecution(val sparkSession: SparkSession, val logical: LogicalPlan) {

  ......其他代码
  
  //analyzer阶段
  lazy val analyzed: LogicalPlan = {
    SparkSession.setActiveSession(sparkSession)
    sparkSession.sessionState.analyzer.executeAndCheck(logical)
  }


  //optimizer阶段
  lazy val optimizedPlan: LogicalPlan = sparkSession.sessionState.optimizer.execute(withCachedData)
  
  //SparkPlan阶段
  lazy val sparkPlan: SparkPlan = {
    SparkSession.setActiveSession(sparkSession)
    // TODO: We use next(), i.e. take the first plan returned by the planner, here for now,
    //       but we will implement to choose the best plan.
    planner.plan(ReturnAnswer(optimizedPlan)).next()
  }

  //prepareForExecution阶段
  // executedPlan should not be used to initialize any SparkPlan. It should be
  // only used for execution.
  lazy val executedPlan: SparkPlan = prepareForExecution(sparkPlan)

  //execute阶段
  /** Internal version of the RDD. Avoids copies and has no schema */
  lazy val toRdd: RDD[InternalRow] = executedPlan.execute()

  ......其他代码
}

Vale ressaltar que cada estágio utiliza carregamento lento e preguiçoso.Se você está interessado nesta peça, pode ver o meu artigo anterior Scala Functional Programming (6) Lazy Loading and Stream .

O exemplo acima apresenta principalmente o conteúdo do módulo Spark SQL, seus antecedentes e principais problemas. A seguir, introduza brevemente o conteúdo da API Dataframe e a estrutura interna do Spark SQL analisando o SQL Catalyst. O acompanhamento apresentará principalmente o processo de cada etapa no Catalyst e fará algumas análises em combinação com o código-fonte.

Acima ~

Acho que você gosta

Origin www.cnblogs.com/listenfwind/p/12724381.html
Recomendado
Clasificación