### 使用Spark Shell进行交互式分析
#### 基础
Spark的shell提供了一个学习API的简单方法,也是一个交互式分析数据的强大工具。它可以在Scala(在Java VM上运行,因此是使用现有Java库的好方法)或Python中提供。通过在Spark目录中运行以下代码来启动它:
```
D:\spark-1.6.2-bin-hadoop2.6\bin>spark-shell
```
Spark的主要抽象是一个名为Resilient Distributed Dataset(RDD)。RDD可以通过Hadoop InputFormats(例如HDFS文件)或通过转换其他数据集来创建。让我们从Spark源目录中的README文件的文本中创建一个新的数据集:
```
scala> val textFile = sc.textFile("../README.md")
textFile: org.apache.spark.rdd.RDD[String] = README.md MapPartitionsRDD[5] at textFile at <console>:27
```
您可以直接从数据集中获取值,通过调用某些操作,或者转换数据集来获取新的值
```
scala> textFile.count()
res0: Long = 95 //README.md总共有多少行数据
scala> textFile.first()
res1: String = # Apache Spark //README.md第一行数据
```
现在让我们转换这个数据集到一个新的。我们调用filter返回一个新的数据集与文件中的项目的一个子集。
```
scala> val linesWithSpark = textFile.filter(line => line.contains("Spark")) //transformation操作 含有”Spark“总共有多上行
linesWithSpark: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at filter at <console>:29
scala> linesWithSpark.count() //action操作
res2: Long = 17
```
我们可以把 actions 和 transformations 链接在一起:
```
scala> textFile.filter(line => line.contains("Spark")).count()
res3: Long = 17
```
#### 更多的Rdd操作
RDD actions 和 transformations可用于更复杂的计算。比方说,我们想找到字数最多的单词:
```
scala> textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
res4: Int = 14
```
首先将行映射成一个整型数值产生一个新 RDD。 在这个新的 RDD 上调用 reduce 找到行中最大的个数。 map 和 reduce 的参数是 Scala 的函数串(闭包),并且可以使用任何语言特性或者 Scala/Java 类库。例如,我们可以很方便地调用其他的函数声明。 我们使用 Math.max() 函数让代码更容易理解:
```
scala> import java.lang.Math
import java.lang.Math
scala> textFile.map(line => line.split(" ").size).reduce((a, b) => Math.max(a, b))
res5: Int = 14
```
一种常见的数据流模式是MapReduce,正如Hadoop单词统计一样。Spark可以轻松实现MapReduce流程:
```
scala> val wordCounts = textFile.flatMap(line => line.split(" ")).map(word => (word, 1)).reduceByKey((a, b) => a + b)
wordCounts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[8] at reduceByKey at <console>:30
```
在这里,我们要求flatMap将一行数据集转换为一个数据集的单词,然后组合groupByKey并count计算文件中每个单词的数量作为(String,Long)对的数据集。为了收集我们shell中的字数,我们可以调用collect:
```
scala> wordCounts.collect()
res6: Array[(String, Int)] = Array((package,1), (this,1), (Version"](http://spark.apache.org/docs/latest/building-spark.html#specifying-the-hadoop-version),1), (Because,1), (Python,2), (cluster.,1), (its,1), ([run,1), (general,2), (have,1), (pre-built,1), (YARN,,1), (locally,2), (changed,1), (locally.,1), (sc.parallelize(1,1), (only,1), (several,1), (This,2), (basic,1), (Configuration,1), (learning,,1), (documentation,3), (first,1), (graph,1), (Hive,2), (["Specifying,1), ("yarn",1), (page](http://spark.apache.org/documentation.html),1), ([params]`.,1), ([project,2), (prefer,1), (SparkPi,2), (<http://spark.apache.org/>,1), (engine,1), (version,1), (file,1), (documentation,,1), (MASTER,1), (example,3), (are,1), (systems.,1), (params,1), (scala>,1), (DataFrames,,1), (provides,1), (refer,2)...
```
#### 高效的缓存
Spark还支持将数据集拉入集群范围内的内存缓存。当重复访问数据时,如查询小的“热”数据集或运行迭代算法(如PageRank)时,这非常有用。作为一个简单的例子,让我们标记我们的linesWithSpark数据集被缓存::
```
scala> linesWithSpark.cache()
res7: linesWithSpark.type = MapPartitionsRDD[2] at filter at <console>:29
scala> linesWithSpark.count()
res9: Long = 17
```