Spark编程基础 --pyspark

以前记录的一些笔记,有点懒直接copy了

spark:
    rdd:
        resilient
        distributed
        dataset


    spark由一个sparkContext发启,由各个work节点的执行器执行的并行计算task.
    核心是RDD
    将数据转换成RDD
        1. parallelize, 序列化外来数据,即将外来数据转换成RDD,不提倡使用,因为要将
            所有数据放进一台集群内存中
            eg:         

myfirtrdd = parallelize(["pandas","golang","c","python","numpy","matlib"])


        2.一般从文件中读取一个存储字符串的RDD方法

    lines = sc.textFile("hdfs://master:9000/data")
    lines = sc.textFile("test.txt")

   RDD操作: 转换操作和执行操作
        转换:
                filter: 是过滤的转化操作,生成一个新的RDD,不会改变myfirtadd RDD          

ardd = myfirtadd.filter(lambda x: "a" in x)

                union: 合并两个RDD

   unrdd = ardd.union(ardd1)


                map:  map将RDD中每个元素处理的结果返回

mrdd = ardd.map(lambda x: x+"bkb")

                flatmap:类似map,不同在于 输入一个元素,输出多个元素,
                一个例子可以看出区别:     

 data = sc.parallelize(["hello world", "how are you"])
 mapdata = data.map(lambda x: x.split()).collect()
 output:
        [['hello','world'],['how','are','you']]

 flatmapdata = data.flatMap(lambda x: x.split()).collect()
 output:
     ['hello','world', 'how','are','you']

                distinct(): 去重, 调用网络进行混洗shuffle,(有方法避免)开销很大。
                intersection(rdd): 求交, 调用网络进行混洗shuffle,(有方法避免)开销很大
                subtract(rdd): 去除, 调用网络进行混洗shuffle,(有方法避免)开销很大
                cartesian(rdd): 乱组,开销巨大


        执行:
            count: 数据的大小
                eg: ardd.count()
            countByValue: 返回RDD每个元素的个数
                eg: ardd.countByValue()
                output:
                defaultdict(int, {1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1})

            collect: 获取RDD 所有的数据,调用此函数一定要注意,你的数据量有多大,内存是否够用
                eg: ardd.collect()
            take: take(n) 获取RDD数据n条
                eg: ardd.take(3)
            takeOrdered:  返回n条,n条排好顺序的
                takeOrdered(n)

            top: 返回默认顺序的
                num = sc.parallelize([1,2,3,5,6,8])
                eg: num.top(2)
                    return [8,6]
            reduce: reduce(func) func参数时RDD中的两个元素返回一个新元素. 
                 eg:  data = sc.parallelize([1,2,3,4,5])
                      data.reduce(lambda x,y: x+y)  返回15
            fold: 功能类似reduce只不过它带有初始化值参数
                 eg: data=flod(1)(lambda x,y: x+y)
            aggregate: 这个参数可以返回不同数据类型的值
                eg: num = sc.parallelize([1,2,3,4,5])
                返回总和,与数量
                num.aggragate((0,0),                 #初始化
                     (lambda acc,value:(acc[0]+value, acc[1]+1)),  #累加
                     (lambda acc1,acc2:(acc1[0]+acc2[0],acc1[1]+acc2[1]))) #合并累加器
            foreach: 有时候我们希望对RDD每个元素处理,但是不返回到驱动器程序中,用foreach(func)
            takeSample: 驱动器程序中采样
                takeSample(withReplace, num, [seed])
                withReplace:true/false  是否有放回采样
                num: 采样数据大小
                seed: 随机种子
                eg:

                    num = sc.parallelize([1,2,3,4,5])
                    num.takeSample(false, 1)


    1. 综上RDD与RDD之间是有依赖关系的,spark中会使用lineage graph(谱系图)来纪录不同RDD之间的依赖关系.
    
    2.每一次RDD行动操作时,整个RDD都会从头开始计算,需要避免这种低效的行为,用户可以将中间结果持久化.
    3. class 编程的时候一定要注意:
        class SearchFunc(object):
            def __init__(self, query):
                self.query = query
            def Get(self, rdd):
                return rdd.filter(lambda x: self.query in x)

        spark会将正常self 序列化发送到work节点上,应该尽量避免,可以这样做
            def Get(self, rdd):
                query = self.query
                return rdd.filter(lambda x: query in x) 

    4. 不同的RDD类型间的转换
       1. mean,variance 只适用数值型RDD
       2. join 只能用于键值对RDD
       python可以不用去转换

    5. 持久化(缓存)
      spark是惰性求值,每次执行操作才把RDD都执行一遍,这样每次都执行整个RDD,造成性能下降,所以我们需要将一些RDD保存下来(持久化)

      python中调用persist,默认是持久化到JVM堆空间.

键值对操作:
    spark 提供一些键值对类型的RDD,并且专门提供了一些操作。
    eg: pairs = lines.map(lambda x: (x.split(" "),x))
    python中构建键值对RDD,只需要返回二元元组RDD
        这其实是一对RDD
    Pair RDD转换操作:
        reduceByKey(func): func对每个key相同的元素做reduce
        groupByKey(): 按照key分组
        combineByKey(creater,mergevalue,mergeCombine):
         类似与aggragate,使用不同的返回类型合并相同的键值
         1. 他会遍历分区中所有的元素
         2. 每个元素需要经过 create(创建该键的累加器的初始值),已经存在的需要mergeValue
         3. 由于每个分区都是独立处理的,所以需要合并分区中对应键的累加器
         eg:
            sumCount = pair.combineByKey(
                (lambda x: (x,1)),
                (lambda x,y:(x[0]+y,x[0]+1),
                (lambda x, y: (x[0]+y[0],x[1]+y[1]))
            )
            pair ([(1, 4), (2, 5), (3, 6), (1, 4), (3, 6)])
            sumCount.collectAsMap()
            {1: (8, 2), 2: (5, 1), 3: (12, 2)}
        4. mapValue(func)对pair RDD中的每个值应用map
            eg:
                pair.mapValue(lambda x: x*2).collect()
                output: [(1, 8), (2, 10), (3, 12), (1, 8), (3, 12)]
        5. keys: 返回所有的key
        6. values: 返回所有的value
        7. sortByKey: 按照key排序
        8. subtractByKey(other):  删除other中存在的键值
        9. join(other):两个RDD内联 
            pair ([(1, 4), (2, 5), (3, 6), (1, 4), (3, 6)])
            other ([(1, 8), (2, 10), (3, 12), (1, 8), (3, 12)])
            pair.join(other)
            output:
            [
                 (1,(4,8)),
                 (1,(4,8)),
                 (1,(4,8)),
                 (1,(4,8)),
                 (2,(5,10)),
                 (3,(6,12)),
                 (3,(6,12)),
                 (3,(6,12)),
                 (3,(6,12))
            ]
        10. rightOuterJoin  右连
        11. leftOuterJoin  左连
        12. cogroup 类似交叉连


            )
    行动操作:
        countByKey:统计每个key的数量
        collectAsMap: python中以字典的形式,但是相同的key只会显示一个值
        lookup(key): 返回key的值
    数据分区:
        为了提供性能,减少网络开销,回对数据经行分区,
        比如,键值对的聚合操作,就希望,每一种key的数据在一个分区中,可以调用
        转换操作: partitionBy(100),建立100个哈希分区
        也可以自定义分区:
            import urlparse
            def hash_domain(url):
                return hash(urlparse.urlparse(url).netloc)     
            rdd.partitionBy(20, hash_domain)
读取数据与保存数据:
    文本文件:
        文件读取:
            textFile(path)  path也可以是目录,也支持通配符,如 part*.txt
            wholeTextFiles(path)返回 一个pair RDD,key 是文件名
        保存文件:
            saveAsTextFile(path)
    JSON文件:
        读取:
            import json
            data = input.map(lambda x: json.loads(x))
        保存文件:
            (data.filter(lambda a: a["love"]).map(lambda x: json.load(x))).saveAsTextFile(/mydata)
    CSV文件:
        解析:

def load(line):
     #解析一行纪录
     input = StringIO.StringIO(line)
     reader = csv.DictReader(input, fieldnames=["name", "Animal"])
     return reader.next()
input = sc.textFile(inputFile).map(load)            
def loadRecords(fileNameContents):
     #解析文件中所有的纪录
   input = StringIO.StringIO(fileNameContents[1])
   reader = csv.DictReader(input, fieldnames=["name", "Animal"])
   return reader
fullfiledata = sc.wholeTextFiles(inputFile).map(loadRecords)


        CSV保存:     

 def writeRecords(records):
     output = StringIO.StringIO()
     writer = csv.DictWriter(output, fieldnames=["name","Animal"])
     for recore in records:
           writer.writerow(recore)
     return [output.getvalue()]
 pandasdata.mapPartitions(writeRecords).saveAsTextFile('/myoutput')

    sequenceFile文件:
        读取:
            data = sc.sequenceFile(inFile, "org.apache.hadoop.io.Text", "org.apache.hadoop.io.InWritable")
        保存:
            data.saveAsSequenceFile(outputFile)
    HDFS文件:
        类似与文本文件
    结构化数据hive:

from pyspark.sql import HiveContext
hiveCtx = HiveContext(sc)
rows = hiveCtx.sql(sql)
firstRow = rows.first()

tweets = hiveCtx.jsonFile("t.json")
tweets.registerTemTable("tweets") 系那个t.json数据注册为一张表
result = hiveCtx.sql("select user.name, text from tweets")查询这张表

连接到Hbase,elasticsearch.

猜你喜欢

转载自blog.csdn.net/weixin_39594447/article/details/87921365