详细指南 在Windows 10上设置Apache Spark开发环境


简介

在我的上一篇文章中,我已经介绍了如何在Windows上设置和使用Hadoop。现在,这篇文章是关于在Windows操作系统上为Apache Spark配置一个本地开发环境。

Apache Spark是最流行的集群计算技术,为快速和可靠的计算而设计。它提供了隐含的数据并行性和默认的容错。它很容易与HIVE和HDFS集成,并提供了一个无缝的并行数据处理的经验。你可以在 https://spark.apache.org 阅读更多关于Spark的信息。

默认情况下,Spark SQL项目不在Windows操作系统上运行,需要我们先进行一些基本的设置;这就是我们在这篇文章中要讨论的,因为我没有在互联网上或书中找到很好的记录。

这篇文章也可用于在Mac或Linux上建立Spark开发环境。只要确保你从Spark的网站上下载了正确的操作系统版本。  

你可以从GitHub这里参考本文中使用的Scala项目。 https://github.com/gopal-tiwari/LocalSparkSql .

期待什么

在本文结束时,你应该能够在Windows操作系统上创建/运行你的 Spark SQL 项目和 spark-shell。

我把这篇文章分为三个部分。你可以根据你的具体使用情况,遵循这三种模式中的任何一种。

你可能也喜欢。 《Apache Spark大全》[教程和文章]

Spark本地开发设置模式

  1. 单一项目访问 (单一项目单一连接)
  2. 设置时间:15分钟
    功能性。有限

  • 每个项目都会有自己的元存储和仓库。
  • 一个项目创建的数据库和表将不能被其他项目访问。
  • 每次只有一个Spark SQL项目可以运行或执行。
  • 多项目访问 (多项目单一连接)

    设置时间:20分钟
    功能。扩展

    • 每个项目将共享一个共同的元存储和仓库。
    • 一个项目创建的表将被其他项目或spark-shell访问。
    • 它将提供一种类似集群的感觉。
    • 每次只有一个Spark SQL项目可以运行或执行。
  • 全集群一样的访问 (多项目多连接)

    设置时间:40分钟
    功能。

    • 这种配置有点繁琐,但一次性的设置将授予你为一个元存储打开多个连接的能力。
    • 在功能方面,你的本地系统和集群不会有任何区别。
    • 数据库和表将在所有Spark项目或shell共享。
    • 你可以在同一时间持续运行多个spark-shell或Spark项目。
  • Spark错误的解决方案

    许多人可能已经尝试在Windows上运行spark,在运行项目时可能面临以下错误。

    16/04/02 19:59:31 WARN NativeCodeLoader: Unable to load native-hadoop library for
    your platform... using builtin-java classes where applicable
    1604/02 19:59:31 ERROR Shell: 未能在 hadoop
    二进制路径中找到 winutils 二进制文件 java.io.IOException: 无法在Hadoop二进制文件中找到可执行文件 null\bin\winutils.exe

    这是因为你的系统没有用于Windows操作系统的Hadoop二进制文件。

    你可以按照我之前的 文章 建立一个,或者从 https://github.com/cdarlint/winutils 下载一个。

    下面的错误也与Windows操作系统的本地Hadoop二进制文件有关。

    16/04/03 19:59:10 ERROR util.Shell: 未能在
    hadoop二进制路径中找到winutils二进制文件 java.io.IOException: 无法在Hadoop二进制文件中找到可执行文件
    C:\hadoop\bin\winutils.exe。

    解决办法是一样的。我们需要用Native Windows二进制文件来设置 HADOOP_HOME

    所以,只要跟着这篇文章走,在本教程结束时,你应该能够摆脱所有这些错误。

    下载所需文件

    1. 根据你的操作系统和CPU架构,从 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 下载并安装JDK。
    2. 根据你所使用的Spark版本安装Scala版本,从   https://www.scala-lang.org/download/all.html
    3. https://www.7-zip.org/download.html 下载并安装7-zip。
    4. http://spark.apache.org/downloads.html 下载并使用 7-zip 解压 Apache Spark 。
    5. https://github.com/cdarlint/winutils 下载 zip 或克隆 Hadoop Windows 二进制文件 。
    6. 如果你没有安装IDE,请安装一个。Intellij IDEA是首选,你可以从 https://www.jetbrains.com/idea/download/#section=windows 获得社区版。
    7. 如果你的系统没有预装Microsoft Visual C++ 2010 Redistributable Package,请下载这些软件。
      1. https://www.microsoft.com/en-us/download/details.aspx?id=5555 .
      2. https://www.microsoft.com/en-us/download/details.aspx?id=14632 .

    对于32位(x86)操作系统,你只需要安装a.,对于64位(x64)请安装a.和b.。

    对于本教程,我们假设Spark和Hadoop二进制文件在你的   C:\ 驱动器中解压。然而,你可以在你系统中的任何位置解压它们。

    设置和安装

    JDK

    在我们进一步进行之前,让我们确保你的Java设置是正确的,环境变量也是根据Java的安装目录更新的。

    要确认Java已经安装在你的机器上,只需打开cmd并输入 java –version 你应该可以看到你的系统上安装的Java的版本。

    如果你得到一个错误信息,如"'java'未被识别为内部或外部命令、可操作程序或批处理文件",那么请遵循以下步骤。否则,跳过它。

    1. 执行下载的JRE和JDK设置,以默认设置完成安装。
    2. 现在,打开系统环境变量对话框
    • 对于Windows 7 ,右击 我的电脑 并选择 属性> 高级
    • 对于Windows 8 ,进入 控制面板 > 系统 > 高级系统设置
    • 对于Windows 10 ,进入 控制面板 > 系统和安全 > 系统 > 高级系统设置
  • 点击 环境变量 按钮。
  • 系统变量 部分点击 新建... 按钮。然后,在 变量名称 字段中输入 JAVA_HOME ,在   变量值 字段中提供你的JDK安装路径。
  • 如果路径包含空格,使用缩短的路径名称--例如, C:\Progra~1\Java\jdk1.8.0_74
  • 对于64位系统的Windows用户
    • Progra~1 = 'Program Files'
    • Progra~2 = 'Program Files(x86)'
    它应该是这样的。  

    Adding new system variable

    添加新的系统变量

  • 现在点击 ok
  • 然后,在你刚刚打开的 环境变量 对话框下的 系统变量 部分搜索 路径 变量。
  • 编辑路径,点击 编辑文本 新建 按钮,在其末尾添加";%JAVA_HOME%\bin"。
  • Adding "%JAVA_HOME%\bin" to PATH

    在PATH中加入"%JAVA_HOME%\bin"

    Environment variables

    环境变量

  • 确认Java的安装,打开一个新的cmd并输入 java –version ,你应该可以看到你刚安装的Java的版本。
  • Checking version of Java installed

    检查安装的Java版本

    如果你的命令提示符有点像上面的图片,你就可以了。否则,你需要检查你的安装版本是否与你的操作系统架构相匹配(x86,x64)。环境变量的路径也可能不正确。

    Scala

    1. 你可能需要安装Scala,这取决于你的Spark的版本。
    2. 对于这篇文章,我们将使用Spark 2.4.4和Scala 2.12.10。
    3. 只要执行下载的 s cala-2.12.10.msi ,并按照安装说明操作即可。
    4. 为了确认Scala的安装,打开cmd并输入 scala –version 。你的命令提示符应该如下图所示。
    5. Checking Scala version

      检查Scala版本

    IntelliJ IDEA设置

    1. 你可以用Scala插件来设置Eclipse,或者直接安装IntelliJ IDEA。
    2. 你可以在首次设置界面选择安装Scala插件,或者从 Settings > plugin > Search 中选择安装Scala。
    3. 如果你在安装插件时遇到VPN代理问题,可以选择离线安装插件。
    4. 确保 文件>设置>插件 窗口显示Scala插件已经安装,如下图所示。
    5. Scala plugin installation

      Scala插件安装

    Hadoop首页设置

    1. 用7-zip打开你下载的GitHub repo https://github.com/cdarlint/winutils (即winutils-master.zip)。
    2. 在这里面,你会发现文件, hadoop-2.7.7 。现在,把它解压到 C:\ 驱动器上。
    3. 你的 C:\hadoop-2.7.7\bin 目录应该看起来像下面的图片。
    4. C:\hadoop-2.7.7\bin directory

      C:\hadoop-2.7.7\bin目录

    5. 一旦提取完成,我们需要添加一个新的 HADOOP_HOME 系统环境变量。
    6. 要添加一个 HADOOP_HOME ,打开 环境变量 对话框,在 系统变量 部分点击 新建... 按钮,填写 名称 文本框,如下图所示。
    7. Adding HADOOP_HOME variable

      添加HADOOP_HOME变量

    Spark首页设置

    1. 用7-zip打开你下载的Spark gz文件(即spark-2.4.4-bin-hadoop2.7.gz)。
    2. 在这里面,你会发现tar文件 s park-2.4.4-bin-hadoop2.7 。双击它,将 s park-2.4.4-bin-hadoop2.7 目录解压到 C:\ 驱动器。
    3. Copying Hadoop file to C:\ drive

      复制Hadoop文件到C:\驱动器

    4. 你的 C:\ spark-2.4.4-bin-hadoop2.7 目录应该看起来像下面的图片。
    5. C:\ spark-2.4.4-bin-hadoop2.7 directory

      C:\ spark-2.4.4-bin-hadoop2.7目录

    6. 一旦提取完成,我们需要将Spark bin目录添加到系统环境 "路径 "变量中。
    7. 编辑路径变量,添加 "C:\spark-2.4.4-bin-hadoop2.7\bin",如下图所示。
    8. Editing environment variables

      编辑环境变量

    注意:如果你没有管理员权限来添加环境变量,不用担心,因为你可以在你的IDE中为每个项目单独设置它。这个过程将在下面的章节中解释。

    单一项目访问

    现在,让我们创建一个名为 "LocalSparkSql "的Scala-Maven新项目。或者,你也可以从GitHub上克隆它。 https://github.com/gopal-tiwari/LocalSparkSql .

    项目结构看起来像这样。

    initial project structure

    初始项目结构

    LocalSparkHiveTest.scala

       package org.connected.spark
    
    import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}
    
    object LocalSparkHiveTest {
    
      def main(args: Array[String]): Unit = {
    
        val spark: SparkSession = SparkSession.builder()
          .enableHiveSupport()
          .master("local")
          .appName("Demo")
          .getOrCreate()
    
        spark.sql("SHOW DATABASES").show
        spark.sql("CREATE DATABASE IF NOT EXISTS sparkdemo")
        spark.sql("CREATE TABLE IF NOT EXISTS sparkdemo.table1(id INT, name STRING)")
        spark.sql("SHOW DATABASES").show
        
        import spark.implicits._
        val df:DataFrame = Seq(
          (1, "One"),
          (2, "Two"),
          (3, "Three")
        ).toDF("id","name")
    
        df.write.mode(SaveMode.Append).format("hive").saveAsTable("sparkdemo.table1")
        //Thread.sleep(60 * 1000)
        spark.sql("SELECT * FROM sparkdemo.table1").show(false)
        println(spark.sql("select * from sparkdemo.table1").count)
    
      }
    }    


    pom.xml

    
    
          4.0.0  
    
          org.connected.spark  
          LocalSparkSql  
          1.0.0-SNAPSHOT  
    
        
            
                  org.apache.spark  
                s  park-core_2.12  
                  2.4。 4  
            
            
                  org.apache.spark  
                s  park-sql_2.12  
                  2.4.4  
            
            
                  org.apache.spark  
                s  park-hive_2.12  
                  2.4.4  
            
        
    


    现在,让我们右击 "LocalSparkHiveTest" 文件并点击 运行

    错误1

    线程 "main "中出现异常 org.apache.spark.sql.AnalysisException。
    java.lang.RuntimeException: java.io.IOException: (null)命令字符串中的条目。
    null chmod 0733 C:\tmp\hive;
     

    如果你看到上述错误,说明你的 HADOOP_HOME 没有正确设置。

    如果你由于管理权限问题而无法设置系统环境变量,你可以在项目层面上通过下面的几个步骤进行设置,否则,你可以跳到下一个指令。

    1. 进入Intellij屏幕的右上角,编辑配置
    2. Edit configurations

      编辑配置

    3. 从左边的面板上展开应用程序可以添加并选择 LocalSparkHiveTest
    4. Run/Debug configurations

      运行/调试配置

    5. 现在,在环境变量文本框中添加 "HADOOP_HOME=C:\hadoop-2.7.7"  
    6. Adding Environment variables

      添加环境变量

    7. 点击 应用 并关闭对话框。

    现在,让我们再次尝试运行主对象

    错误2

    线程 "main "中出现异常 org.apache.spark.sql.AnalysisException:
    java.lang.RuntimeException: java.lang.RuntimeException: root scratch dir:
    HDFS上的/tmp/hive应该是可写的。当前的权限是。---------;
     

    为了解决这个错误,我们需要打开Hive默认临时目录的权限。

    在这里,我们需要打开你的Hadoop主页,然后进入   /bin 目录并执行以下命令。

    winutils.exe chmod 777 /tmp/hive  

    授予的权限应该是 "drwxrwxrwx",你可以使用下面的命令检查权限状态

     winutils.exe ls \tmp\hive  

    Checking permissions

    检查权限

    错误3

    如果你的机器没有Microsoft Visual C++ 2010 Redistributable Package,你可能得到以下错误。

    由于没有找到MSVCR100.dll,代码执行无法进行。
    重新安装程序可能会解决这个问题。
     

    System error

    系统错误

    你可以从本文的 下载 部分下载并安装C++ 2010 Redistributable Package,因为我在那里提供了直接的下载链接。

    现在,让我们再次执行该项目,你应该可以毫无问题地创建一个数据库和表。

    输出。


    Creating database and table

    创建数据库和表

    现在,你可能已经注意到在你项目的根文件夹下已经创建了两个新的目录, metastore_db spark-warehouse

    Project file structure

    项目文件结构

    这些目录是什么?

    metastore_db:

    Spark SQL使用一个Hive元存储来管理用户创建的数据库和表的元数据信息。你可以认为它是一个小型的关系型数据库,存储了实际的数据库目录路径、表结构、分区列、文件位置等信息。

    默认情况下,Spark带有一个嵌入式Derby Db支持来管理元数据。关于Derby的更多信息可以在这里找到 https://db.apache.org/derby/

    s 公园-仓库。

    仓库目录是一个写入表数据的位置。默认情况下,Spark将该目录创建为spark-warehouse。

    你可以在这里得到更多的信息 https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-hive-metastore.html

    现在,如果我们用我们用于 LocalSparkSql   项目的相同代码创建另一个新项目,我们可以注意到,我们无法访问由我们之前的项目创建的数据库" s parkdemo" 。这种行为背后的原因是,对于每个项目, metastore_db s park-warehouse 都会被重新创建,而且它们是特定于该项目的,因为它们被创建在项目的根目录下。

    然而,我们可以连接到其他项目的metastore和仓库,但更好的方法是创建一个共同的独立的metastore_db和spark-warehouse目录,并通过向SparkSession添加一些额外的配置在多个项目之间共享,这就是我们将在下一节讨论的内容。


    多项目访问

    为了模拟这种行为,我们需要创建一个新的项目并尝试访问一个共同的 metastore_db 和仓库。

    在这个演示中,我们将使用目录位置,如下所示。

    对于metastore_db C:\tmp\hive\metastore_db

    对于warehouse C:\tmp\hive\spark-warehouse

    配置Spark-Project

    为了让Spark引用我们新的公共目录,我们需要在创建Spark会话对象的时候添加以下配置。

    s park.sql.warehouse.dir = C:/tmp/hive/spark-warehouse

    javax.jdo.option.ConnectionURL = jdbc:derby:;databaseName=C:/tmp/hive/metastore_db;create=true  

    代码应该看起来像。

       val spark: SparkSession = SparkSession.builder()
      	.enableHiveSupport()
      	.master("local")
      	.appName("Demo")
      	.config("spark.sql.warehouse.dir","C:/tmp/hive/spark-warehouse")
    	.config("javax.jdo.option.ConnectionURL","jdbc:derby:;databaseName=C:/tmp/hive/metastore_db;create=true")
      .getOrCreate()    


    你需要在你的每个项目中使用上述配置,让项目访问其他应用程序创建的数据库和表。

    配置Spark-Shell

    现在,为了检查上述配置的有效性,我们可以启动一个spark-shell并尝试访问一个" s parkdemo" 数据库和 "table1"。

    在我们启动spark-shell之前,我们需要通过以下步骤将其配置为指向我们的公共元存储和仓库。

    1. 进入Spark配置目录,   C:\spark-2.4.4-bin-hadoop2.7\conf
    2. 创建或重命名已经存在的文件 " s park-defaults.conf.template"   "spark-defaults.conf"
    3. 在文件的末尾添加以下两行。  
      1. spark.driver.extraJavaOptions -Dderby.system.home=C:/tmp/hive  
      2. spark.sql.warehouse.dir C:/tmp/hive/spark-warehouse  
    4. 现在,打开一个新的cmd,从   C:\spark-2.4.4-bin-hadoop2.7\bin 目录中运行 spark-shell

    现在,让我们试着通过运行 SHOW DATABASES 并在shell中选择table1的所有数据来列出所有的数据库。

    Selecting * from table1

    Selecting * from table1

    上述结果验证了我们的共享元存储配置是正确的,因为我们能够访问由上述代码创建的表。

    现在,如果你继续打开spark-shell,并试图在同一时间点运行你的scala项目,你会得到以下错误。  

    Unable to open a test connection to the given database. JDBC url = jdbc:derby:;databaseName=C:/tmp/hive/metastore_db;create=true, username = APP. Terminating connection pool (set lazyInit to true if you expect to start your database after your app). Original Exception: ------
    
    java.sql.SQLException: Failed to start database 'C:/tmp/hive/metastore_db' with class loader org.apache.spark.sql.hive.client.IsolatedClientLoader$$anon$1@4262fdeb, see the next exception for details.


    这是因为我们使用的是Spark的嵌入式 derbyDb ,一个应用程序(即spark-shell)已经直接连接到共享的 metastore_db 数据库并获得了锁,所以另一个实例无法启动。如果我们可以使用网络服务连接到derby,而不是直接连接到数据库,这种情况是可以避免的。但是,我们没有运行一个derby服务器实例,所以在这种情况下我们不能这样做。

    然而,我们可以在一个单独的关系型数据库中创建Hive元存储,并让Spark连接到该数据库以实现多连接设置。我们将在下一节讨论这个问题。

    类似于集群的完全访问

    为了在这种模式下配置本地元存储,我们需要下载并安装下面列出的一些额外的组件,以及本文" 下载" 部分中指定的其他组件。

    注意:直接跳到文章的这一部分并不是一个好主意,因为你可能会错过一些重要的和必须的步骤,所以请从一开始就按照文章的要求来完成配置。

    下载

    1. 下载并安装MySql社区版。   https://dev.mysql.com/downloads/windows/installer/8.0.html .
    2. 如果你没有SQL GUI编辑器,请安装HeidiSql。   https://www.heidisql.com/download.php
    3. 下载MySql连接器jar,根据你的MySql服务器版本,从 https://dev.mysql.com/downloads/connector/j/ 。确保选择 平**立 作为操作系统来进行。
    4. 下载或打开Hive元存储DDL:   https://raw.githubusercontent.com/apache/hive/master/metastore/scripts/upgrade/mysql/hive-schema-2.3.0.mysql.sql   
    5. 下载Hive事务模式DDL:   https://raw.githubusercontent.com/apache/hive/master/metastore/scripts/upgrade/mysql/hive-txn-schema-2.3.0.mysql.sql

    安装

    MySql:

    1. 运行下载的 mysql-installer-community-8.0.*.*.msi .
    2. 选择安装类型为 自定义
    3. 请至少选择要安装的以下功能。
    4. Installing MySQL Server

      安装MySQL服务器

    5. 在下一页,点击 执行 ,让安装程序从你的系统中下载并安装任何缺失的组件。
    6. 点击 下一个 执行 ,让安装开始。
    7. 安装后,将出现配置页面;让我们选择 独立的MySQL服务器
    8. 选择 开发计算机 作为配置类型,其他设置保留为默认。
    9. 为了简单起见,我们将根密码设置为 "root"。
    10. 保持其他设置为默认值,完成安装。

    HeidiSQL

    1. 現在,執行下載的 HeidiSQL_*_Setup.exe 並以默認設置完成安裝。
    2. 打开HeidiSQL,选择网络类型为 MariaDB MySQL
    3. 提供用户和密码为root(或你配置的用户名和密码),然后点击打开。
    4. 打开一个新的查询窗口,执行以下语句。
      1. CREATE DATABASE metastore_db;  
      2. USE metastore_db;  
    5. 现在,从   hive-schema-2.3.0.mysql.sql   文件中复制Hive元存储ddl的内容。链接。 https://raw.githubusercontent.com/apache/hive/master/metastore/scripts/upgrade/mysql/hive-schema-2.3.0.mysql.sql .
      1. 删除或注释掉第835行,如 "-- SOURCE hive-txn-schema-2.3.0.mysql.sql;"
      2. metastore_db上执行整个DDL
    6. 现在,从 hive-schema-2.3.0.mysql.sql   文件中复制并执行Hive事务性模式的DDL。链接。 https://raw.githubusercontent.com/apache/hive/master/metastore/scripts/upgrade/mysql/hive-txn-schema-2.3.0.mysql.sql .

    一旦这两个SQL文件在你的 metastore_db 上成功执行,你就可以配置你的项目来访问这个metastore了。所以,让我们通过以下步骤来配置spark-shell和Scala/Java项目。

    配置spark-shell

    在我们启动spark-shell之前,我们需要配置它来使用我们常用的MySQL元存储和仓库。请按照以下步骤来配置shell。

    1. 进入Spark配置目录 C:\spark-2.4.4-bin-hadoop2.7\conf
    2. 确保删除文件   "spark-defaults.conf"   或注释掉之前添加的 s park.driver.extraJavaOptions s park.sql.ware.dir 的行。
    3. 现在,创建一个新文件,名称为 hive-site.xml 。然后,在conf目录下添加以下内容。
    4. hive-site.xml  

      
          
                javax.jdo.option.ConnectionURL  
                jdbc:mysql://localhost:3306/metastore_db?ceateDatabaseIfNotExist=true  
                JDBC metastore的JDBC连接字符串  
          
      
          
                javax. jdo.option.ConnectionDriverName  
                com.mysql.cj.jdbc.Driver  
                JDBC元存储的驱动类名称  
          
      
          
                javax.jdo.option.ConnectionUserName  
                root. ConnectionUserName 
               root 
          
      
          
               javax.jdo.option.ConnectionPassword 
               root 
          
      
          
               hive.metastore.warehouse.dir 
               C:/tmp/hive/spark-warehouse 
               仓库默认数据库的位置 
          
      
             
    5. mysql-connector-java-8.0.18.jar 复制到   C:\spark-2.4.4-bin-hadoop2.7\jars\ 目录。你可以从 C:\Program Files (x86)\MySQL\Connector J 8.0\ 得到它,或者使用已经从下载区下载的那个。链接。   https://dev.mysql.com/downloads/connector/j/ .  
    6. 删除旧的仓库目录(即 C:\tmp\hive\spark-warehouse )。否则,我们可能会得到一个 "目录已经存在 "的错误,因为我们正在重复使用同一个目录。
    7. 现在,打开一个新的命令提示符,从   C:\spark-2.4.4-bin-hadoop2.7\bin 目录中运行spark-shell,执行以下代码。
    8.    spark.sql("CREATE DATABASE IF NOT EXISTS sparkdemo")
      
      spark.sql(
      	s"""
      		CREATE TABLE IF NOT EXISTS sparkdemo.table2
      		(
      			id INT,
      			name STRING
      		)
      		PARTITIONED BY(
      		  date STRING
      		)
      		STORED AS PARQUET
      	""")
      
      import org.apache.spark.sql.{DataFrame, SaveMode}
      import spark.implicits._
      
      spark.conf.set("hive.exec.dynamic.partition.mode","nonstrict")
      
      val df2: DataFrame = Seq(
        (1, "One","2020-01-01"),
        (2, "Two","2020-01-03"),
        (3, "Three","2020-01-11")
      ).toDF("id", "name","date")
      
      df2.write.mode("overwrite").insertInto("sparkdemo.table2")
      
      spark.sql("SHOW DATABASES").show
      spark.sql(“SELECT * FROM sparkdemo.table2”).show
      spark.sql("SHOW PARTITIONS sparkdemo.table2").show    


      输出。 Output from SQL commands SQL命令的输出

    现在,我们需要验证我们是否可以打开多个连接到Hive元存储。然后,我们可以检查我们是否可以在本地Windows系统中同时运行多个Spark项目。让我们在下一节中尝试在不关闭当前spark-shell的情况下从一个单独的项目访问元存储。

    配置一个Spark项目

    现在,让我们在 "LocalSparkSql "项目中创建一个新的Scala对象, LocalMySQLMetastoreTest

    在这个对象中,我们将尝试在 s parkdemo.table2 ,   中插入一些更多的记录,这是我们刚刚用spark-shell创建的。

    现在,我们需要提供一些与MySQL服务器地址和证书有关的额外配置,以便它可以被 SparkSession 实例用来连接到我们新的MySQL元存储。

    下面给出了一个配置样本,以及完整的代码。  

    示例

      val spark: SparkSession = SparkSession.builder() 
    .enableHiveSupport() 
    .master("local") 
       ...
    .config("javax.jdo.option.ConnectionURL", "jdbc:mysql://    :    /metastore_db" )
    .config("javax.jdo.option.ConnectionDriverName", "    " )
    .config("javax.jdo.option.ConnectionUserName", "    " )
    .config("javax.jdo.option.ConnectionPassword", "    " )
       ...
    .getOrCreate()  


    由于我们将使用MySQL JDBC进行连接,我们需要在 pom.xml 中添加MySQL JDBC驱动作为依赖,如下图所示。

      
    ...  
            
                   mysql  
                   mysql-connector-java  
                   8.0.18  
              
    ..  
    


    完整代码

    LocalMySQLMetastoreTest.scala
       import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}
    
    object LocalMySQLMetastoreTest {
    
      def main(args: Array[String]): Unit = {
    
        val spark: SparkSession = SparkSession.builder()
          .enableHiveSupport()
          .master("local")
          .appName("Demo")
          .config("spark.sql.warehouse.dir", "C:\\tmp\\hive\\spark-warehouse")
          .config("javax.jdo.option.ConnectionURL", "jdbc:mysql://localhost:3306/metastore_db")
          .config("javax.jdo.option.ConnectionDriverName", "com.mysql.cj.jdbc.Driver")
          .config("javax.jdo.option.ConnectionUserName", "root")
          .config("javax.jdo.option.ConnectionPassword", "root")
          .config("hive.exec.dynamic.partition.mode", "nonstrict")
          .getOrCreate()
    
        import spark.implicits._
        spark.sql("CREATE DATABASE IF NOT EXISTS sparkdemo")
        spark.sql(
          s"""
                      CREATE TABLE IF NOT EXISTS sparkdemo.table2
                      (
                        id INT,
                        name STRING
                      )
                      PARTITIONED BY(
                        date STRING
                      )
                      STORED AS PARQUET
                    """)
    
        val df2: DataFrame = Seq(
          (4, "Four", "2020-01-13"),
          (5, "Five", "2020-01-13"),
          (6, "Six", "2020-01-15")
        ).toDF("id", "name", "date")
        df2.write.mode(SaveMode.Overwrite).insertInto("sparkdemo.table2")
        spark.sql("SELECT * FROM sparkdemo.table2").show
        spark.sql("SHOW PARTITIONS sparkdemo.table2").show
      }
    }    

    pom.xml
    
    
          4.0.0  
    
          org.connected.spark  
          LocalSparkSql  
          1.0.0-SNAPSHOT  
    
        
            
                  org.apache.spark  
                s  park-core_2.12  
                  2.4.4  
            
            
                  org. apache.spark  
                s  park-sql_2.12  
                  2.4.4  
            
            
                  org.apache.spark  
                s  park-hive_2.12  
                  2.4.4  
            
            
                  mysql  
                  mysql-connector-java  
                  8.0.18  
            
        
    


    现在,让我们运行我们的 LocalMySQLMetastoreTest 对象。其输出结果应该如下图所示。

    Output from LocalMySQLMetastoreTest

    LocalMySQLMetastoreTest的输出

    注意:在某些情况下,你可能无法看到其他spark-shell/项目的新添加的分区或数据,因为这是Hive/Spark元存储管理的预期行为。你可以考虑执行ALTER TABLE ADD PARTITIONS或spark.catalog.refreshTable("dbname.tablame")来反映新的数据。

    在用相同的数据再运行一次该项目后,当我试图在我的旧火花-shell中运行 spark.sql("SELECT * FROM sparkdemo.table2").show 时,我得到了以下异常。

    java.io.FileNotFoundException。
    file:/C:/tmp/hive/spark-warehouse/sparkdemo.db/table2/date=2020-01-13/part-000
    00-666cc8ed-b44b-4025-9606-e5d9e660c8db.c000不存在

    这背后的原因很简单,我们从shell外部添加/修改了一些额外的行/分区,所以我们spark-shell的metastore目录并不知道这些变化。

    运行下面的代码将执行元数据的强制更新,并最终解决这个问题

       spark.catalog.refreshTable("sparkdemo.table2")    


    现在,在shell中执行 spark.sql("SELECT * FROM sparkdemo.table2").show 会得到以下的更新结果。

    Updated results

    更新的结果

    结束语

    我希望这个关于设置本地Spark开发环境的扩展演示让你对与本地设置相关的配置有一个全面深入的了解。我已经尽力涵盖了尽可能多的故障情况,但如果你有任何其他问题、疑问或建议,可以在下面的评论中分享。

    感谢阅读!!


    进一步阅读