官方文档:http://spark.apache.org/
1.开始:
Linux命令:spark-submit 加py文件名
py文件开始:
import pyspark
conf=pyspark.SparkConf().setMaster("local").setAppName("My App")
sc=pyspark.SparkContext(conf=conf)
日常使用方法:
collect():返回rdd中的数据。
saveAsTextFile():数据保存操作,把rdd列表里的元素转到文件系统(默认一个元素一行)。传入一个文件地址,文件需要未被创建,原因是如果文件地址不小心相同,可能会发生数据覆盖,数据存在等错误(hadoop权威指南中写的)。
persist():数据持久保持在内存中的操作,spark默认rdd使用一次后就会从内存中移除,好像是模式的原因,先组织好操作步骤(没有先计算),直到行动操作(书上说是reduce,fold,aggregate等会输出的操作,saveAsTextFile,collect等应该也算),然后才计算,用这个(persist)方法,使用后数据仍然保存在内存中。如未使用,想再次用需要再次计算(如,在spark机器学习中对函数的参数进行评估需要重复运算,以找到最合适的参数),重新计算会浪费一些时间和资源,用这个方法后就会保存在内存中,下次就可以直接用。如可以在保持分区的情况,像一些需要混洗的操作(就是需要明确查找,如排序等,需要hash()等分区后,才可以找到),如果频繁使用,每次不但要重新计算,还需要重新hash()分区,浪费时间和资源。后面的操作如果不发生可以改变分区的操作,保存还可以持续。不要担心内存满了怎么办,好像是有机制的吧,很多都是书上写的,具体单机也无从考证,不过挺有道理的。
2.方法:
(1)数据读入方法:
textFile():读取一个文件的地址,以单行为一条数据
wholeTextFiles():读取一个文件夹地址,以其中所有的目标文件为数据,一个文件作为一条二元组型(key-value)数据,文件地址为key,文件内容为value,如:("file///:home/hadoop/spark/test","0\n1\n2\n3\n")
parallelize():传入一个list
注意:文件末尾尽量在数据末尾,随手一个回车就会增加一条数据,数据处理方式不对可能会报错,测试在Linux默认文件系统下完成,其它的文件系统如S3,hdfs等自行测试。
(2)单行数据Value处理方法:
map():传入一个方法,这个方法会逐条处理每一条数据,新的集为传入方法return的内容。
count():返回rdd内的数据个数。不是rdd,下面很多如:reduce,fold,aggregate等也是这样。
take():传入一个数字,返回数字个数的元素的rdd。相类似的还有top()。
flatmap():传入一个方法,逐条处理数据,与map()不同的是,return返回的内容如果是list列表,将会被自动切分,如:return ["coffee","panda"] flatmap()会自动切分成["coffee","panda",加其它数据],而map()会是这样的[["coffee","panda"],加其它数据]。
filter():传入一个函数,在函数体内进行筛选,return一个bool型,返回ture会被保留,其它的不会保留。
countByValue():各元素在rdd中出现的个数,用字典格式包装,如一个"panda"数据,会是这样:defaultdict(
reduce():把所有数据结合成一条数据,传入一个包含两个形参的方法,第一个形参为第一个数据或者前面方法结合的半成品(学名叫Combiner组合器),第二个为后面需要结合的数据,用最简单的lambda写一个累加方法,如:(lambda x,y:x+y)。分区:因为在单机测试,强行通过partitionBy(2)增加一个分区会报没有数据的错误,应该有分区聚合操作,具体不知。
fold():传入一个初始值,可以为其它格式,比如(0,0),再传入一个函数,包含两个形参,第一个形参为初始值或处理后的半成品,第二个为需要处理的数据,如计算平均值:先map(lambda x:(int(x),1)),再fold((0,0),(lambda x,y:(x[0]+y[0],x[1]+y[1])) 最后得到一个二元组(累加数,数据个数),平均值=二元组[0]/二元组[1]。分区:因为是单机模式,强行分区会报数据不足的错误,但根据print打印中间结果分析,每个分区算出各自的结果(使用一次初始值),然后仍然是用传入的函数,用初始值把各分区的结果加起来(再次使用初始值)。
aggregate():传入三个参数,第一个是初始值,第二个是分区内的计算函数,第三个是分区间的计算函数。这个函数结合了map()和fold(),提高了性能,如计算平均值aggregate((0,0),(lambda x,y:(x[0]+int(y),x[1]+1)),(lambda x,y:(x[0]+y[0],x[1]+y[1])))。结果和上面的fold()一样,节省了一步操作,提高了性能。分区:和fold()相似,不同的是分区内和分区间用的不是同一个函数。
distinction():去除rdd中的重复数据,如:[1,2,1,1,1].distinct(),结果是[1,2]。
(3)两个rdd之间的“伪集合操作”(学了一些基础的,没发现“真-集合操作”):
union():传入一个rdd,返回一个包含两个rdd中所有元素的rdd。这个是rdd数据间的相加(+)操作。
subtract():传入一个rdd,返回 使用这个方法的rdd里的数据 移除 和传入rdd中相同的数据。这个是rdd数据间的相减(-)操作。
intersection():仍然只传入一个rdd,返回两个rdd中相同的数据,自带distinction()操作,如:[1,2,3,3].intersection([3,4,5]),结果是[3]。虽然看不出速度咋样,书上说因为需要数据混洗,效率比union()差,想一下也对,毕竟要找相同的元素,随便hash()分区一下也会消耗时间和资源。这个是rdd数据间的相交(倒着的U)操作。
cartesian():还是传入一个rdd,返回两个rdd之间的笛卡儿积,以二元组包装,如:[1,2].cartesian([3,4]),结果是[(1,3),(1,4),(2,3),(2,4)]。这是rdd数据间的相乘(*)操作,没发现相除方法,没有头绪。