# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/22 下午4:55 # @IDE : PyCharm from _operator import add from Init_SparkContext import MySparkContext sc = MySparkContext().open() fruits = sc.parallelize([("a", ["apple", "banana", "lemon"]), ("b", ["grapes"]), ("a", ["apple2", "banana2"])]) """ mapValues():对键值对RDD中的每个value都应用一个函数,但是,key不会发生变化 reduceByKey():对具有相同key的键值对进行合并 """ t = fruits.mapValues(lambda x: len(x)) t2 = t.reduceByKey(add) print("\n{0}\n{1}".format(t.collect(), t2.collect())) # print("\n{0}\n{1}".format(t.collect(), type(t2))) t3 = fruits.mapValues(lambda x: (x, 1)).reduceByKey(lambda x, y: (x[0] + y[0], x[1] + y[1])) print(t3.collect()) """ combineByKey() 是最为常用的基于键进行聚合的函数。大多数基于键聚合的函数都是用它 实现的 如果这是一个新的元素,combineByKey()会使用一个叫作 createCombiner() 的函数来创建那个键对应的累加器的初始值。 -- 需要注意的是,这一过程会在每个分区中第一次出现各个键时发生,而不是在整个 RDD 中第一次出现一个键时发生。 如果这是一个在处理当前分区之前已经遇到的键,它会使用 mergeValue() 方法将该键的累 加器对应的当前值与这个新的值进行合并。 由于每个分区都是独立处理的,因此对于同一个键可以有多个累加器。 如果有两个或者更 多的分区都有对应同一个键的累加器,就需要使用用户提供的 mergeCombiners() 方法将各 个分区的结果进行合并。 """
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/2/19 上午11:09 # @IDE : PyCharm """ 利用分区优化charpter1行动操作.py的平均值计算过程 每个分区只创建一次二元组,而不用为每个元素都执行这个操作 """ from _operator import add from Init_SparkContext import MySparkContext sc = MySparkContext().open() rdd = sc.parallelize([121, 28, 63, 214, 88]) def partitionCtr(nums): """计算分区的sumCounter""" sumCount = [0, 0] for num in nums: sumCount[0] += num sumCount[1] += 1 return [sumCount] def fastAvg(nums): """计算平均值""" sumCount = nums.mapPartitions(partitionCtr).reduce(add) print("计算所得总和为:%f,平均值为:%f" % (sumCount[0], sumCount[0] / float(sumCount[1])))
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/19 下午6:07 # @IDE : PyCharm """ 两个最常用的转化操作是 map() 和 filter() - map: 接收一个函数,把这个函数用于 RDD 中的每个元素,将函数的返回结果作为结果RDD中对应元素的值 - filter: 接收一个函数,并将 RDD 中满足该函数的 元素放入新的 RDD 中返回 """ from Init_SparkContext import MySparkContext sc = MySparkContext().open() # 利用map计算平方 nums = sc.parallelize([1, 2, 3, 4]) squared = nums.map(lambda x: x * x).collect() for num in squared: print("%i" % num) """ 提供给 flatMap() 的函数被分别应用到了输入 RDD 的每个元素上。不 过返回的不是一个元素,而是一个返回值序列的迭代器。 输出的 RDD 倒不是由迭代器组 成的。我们得到的是一个包含各个迭代器可访问的所有元素的 RDD """ # 利用flatMap()将行数据切分为单词 lines = sc.parallelize(["hello world", "hi"]) words = lines.flatMap(lambda line: line.split("")) print(words.first())
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/19 下午4:24 # @IDE : PyCharm from Init_SparkContext import MySparkContext # 向spark传递函数 log_path = '../../test.log' rdd = MySparkContext().read_data(log_path) def contains_error(s): return "error" in s word = rdd.filter(contains_error) # 传递一个带字段引用的函数 class SearchFunctions(object): def __init__(self, query): self.query = query def is_match(self, s): return self.query in s # 以下两种方法不推荐 def get_matches_function_reference(self, rdd): # 问题:在"self.isMatch"中引用了整个self return rdd.filter(self.is_match)
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/22 上午9:55 # @IDE : PyCharm from Init_SparkContext import MySparkContext sc = MySparkContext().open() lines = sc.parallelize( ["sacajawea", "recedes", "hello", "haft vaderA Sabbath", "www"]) # 使用第一个单词作为键(这里是以空格划分单词)创建出一个 pair RDD pairs = lines.map(lambda x: (x.split(" ")[0], x)) # 根据字符长度进行筛选 result = pairs.filter(lambda KeyValue: len(KeyValue[1]) > 7) print(result.collect()) """ map和flatMap的区别: map():对每一条输入进行指定的操作,然后为每一条输入返回一个对象 flatMap(): 操作1:同map函数一样:对每一条输入进行指定的操作,然后为每一条输入返回一个对象 操作2:最后将所有对象合并为一个对象 """ rdd = sc.parallelize([2, 3, 4]) print(rdd.map(lambda x: list(range(1, x))).collect()) print(rdd.flatMap(lambda x: range(1, x)).collect())
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/25 下午2:28 # @IDE : PyCharm import json from Init_SparkContext import MySparkContext sc = MySparkContext().open() # 读取文本文件 text = sc.textFile('../test.log') info = text.filter(lambda s: "error" in s) info.saveAsTextFile('test') # 读取json数据 data = sc.textFile('test.json') data = data.map(lambda x: json.loads(x)) data.foreach(lambda x: print(x))
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/1/17 下午5:46 # @IDE : PyCharm from Init_SparkContext import MySparkContext # 读取数据(因为spark的惰性求值,此时并没有真正读取进来数据) log_path = '../../test.log' rdd = MySparkContext().read_data(log_path) # 用filter进行转化操作 errorsRDD = rdd.filter(lambda s: "error" in s and "INFO" not in s) warningsRDD = rdd.filter(lambda s: "WARN" in s) # 进行union转化操作 badLinesRDD = errorsRDD.union(warningsRDD) # 行动操作对错误进行计数 print("Input concerning lines:%d" % badLinesRDD.count()) print("\nHere are 10 examples:") for line in badLinesRDD.take(10): print(line) """ RDD 还有一个 collect() 函数,可以用来获取整个RDD 中的数据 但是只有当你的整个数据集能在单台机器的内存中放得下时,才能使用collect() 每当我们调用一个新的行动操作时,整个RDD都会从头开始计算。要避免这种低效的行为,用户可以将中间结果持久化 """
# @Author : adair_chan # @Email : [email protected] # @Date : 2019/2/13 下午7:25 # @IDE : PyCharm """ 注意,工作节点上的任务不能访问累加器的值。从这些任务的角度来看,累加器是一个只写变量 """ import re from _operator import add from Init_SparkContext import MySparkContext sc = MySparkContext().open() # 累加空行 file = sc.textFile('../test.log') # 创建Accumulator[int]并初始化为0 blankLines = sc.accumulator(0) def extractCallSigns(line): global blankLines # 访问全局变量 if line == "": blankLines += 1 return line.split(" ") callSigns = file.flatMap(extractCallSigns) callSigns.saveAsTextFile("callSigns") print("Blank lines: %d" % blankLines.value)