JVM 是必须的,所以需要 Java(JDK 1.8+), 想写 Python 的还需要 Python(2.7.x/3.x).

快速试用或简单尝试的,可以考虑 databrick cloud 或者本地安装 spark-notebook/spark-notebook 可以在浏览器中写 Scala 代码体验一些 Spark 和 Scala 的特性。

对于 Spark 的安装,去官方页面下载选中的编译好压缩包即可,解压即用。其中 1.x(1.6.3) 在一些老的集群中还在大量使用,但基本不再有新的功能加入。2.x(2018 年 2 月底 2.3.0 引入了大量新的 feature) 开发非常活跃,API 的便利性和性能都有较大提升,推荐使用。基于 Spark 的开发模式往往比较重,如果使用 IDE 的话推荐使用 IntelliJ IDEA 进行开发,安装好 Scala 和 Python 插件。

Windows

Windows 下使用 Spark 需要做的准备工作稍微多一点点,设置 Spark 环境 SPARK_HOME 为 Spark 解压目录 D:\spark\spark-1.6.3-bin-hadoop2.6. 尽管 Spark 在本地运行并不需要完整的 Hadoop 环境,但还是间接依赖了一些 Hadoop 提供的文件操作工具,故在 Windows 下需要一些 POSIX 的文件权限操作,因此我们需要 winutils.exe. 作者在 steveloughran/winutils 上放出了预编译好的二进制版本,按需选择即可。需要注意的是 winutils.exe 需要置于 HADOOP_HOMEbin 目录下,我们可以新建 D:\hadoop 作为 HADOOP_HOME 变量。变量设置好后需要判断这两个环境变量是否生效。

PySpark

使用 PySpark 时最重要的环境变量是 PYTHONPATHspark-submit 提交时 --py-files Python 及其依赖的打包注意事项。

#!/usr/bin/env bash

set -e

export SPARK_HOME=${SPARK_HOME:="/usr/hdp/2.6.1.0-129"}
export PYTHONPATH=$SPARK_HOME/python:$SPARK_HOME/python/lib/py4j-0.9-src.zip:$SPARK_HOME/python/lib/pyspark.zip:$PYTHONPATH
export SPARK_MASTER=${SPARK_MASTER:="local[*]"}


spark-submit \
    --master \
    ${SPARK_MASTER} \
    --deploy-mode \
    client \
    --name \
    PySpark \
    --verbose \
    main.py $@

Scala

使用 Scala 来开发 Spark 程序是最为 native 的方式,也没有性能惩罚,是我个人最喜欢的方式。考虑到我们通常并不将 Spark 的核心包打包至最终的 jar 包提交,我们可以在 build.sbt 中指定 Spark 相关依赖为 provided, 完整的 build.sbt 见下文。

name := "scala-ml-text"

organization := "com.yintech"

version := "1.0"

scalaVersion := "2.10.7"

val sparkVersion = "1.6.3"

lazy val sparkDependencies = Seq(
  "org.apache.spark" %% "spark-core" % sparkVersion,
  "org.apache.spark" %% "spark-mllib" % sparkVersion,
  "org.apache.spark" %% "spark-hive" % sparkVersion
)

libraryDependencies ++= Seq(
  "log4j" % "log4j" % "1.2.17",
  "org.slf4j" % "slf4j-log4j12" % "1.7.10",
  "com.typesafe" % "config" % "1.2.1",
  "com.databricks" % "spark-csv_2.10" % "1.5.0"
)

libraryDependencies ++= sparkDependencies.map(_ % "provided")

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", xs @ _*) => MergeStrategy.discard
  case x => MergeStrategy.first
}