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
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:
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.
O processo principal pode ser dividido aproximadamente nas seguintes etapas:
- 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)
- O analisador e o catálogo são vinculados (metadados das lojas de catlog) para gerar o Plano Lógico;
- O otimizador otimiza o plano lógico e gera o LogicalPlan otimizado;
- O SparkPlan converte o LogicalPlan otimizado em plano físico;
- prepareForExecution () converte o Plano Físico em Plano Físico executado;
- 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 ~