【python】pyspark详解

为了更好地进行大数据分析与处理,最近在学习PySpark,整理了一下笔记 ,加深印象。

1 Resilient Distributed Datasets(RDD)

弹性分布式数据集(RDD)是一个不可变的JVM对象的分布式集合,是Spark的基本抽象。

1.1 创建RDD
准备工作:

>>> import pyspark
>>> from pyspark import SparkContext
>>> from pyspark import SparkConf
>>> conf = SparkConf().setAppName('project1').setMaster('local')
>>> sc = SparkContext.getOrCreate(conf)

在PySpark里有两种方法创建RDD:
一是,.parallelize(…) 个collection集合 ( list or an array of some elements)。

>>> data = sc.parallelize([('amber',22),('alfred',23),('skye',4),('albert',12),('amber',9)])

二是,引用位于本地或HDFS上的某个文件(或多个文件)。

>>> data_from_file = sc.textFile('/home/qml/pyspark-ex/VS14MORT.txt.gz',4)
# sc.textFile(...,n)中的最后一个参数指定数据集被分区的数量,经验是分成两个四分区

# sc.textFile(…,n)中的最后一个参数指定数据集被分区的数量,经验是分成两个四分区

Spark 支持多种数据格式:可以使用JDBC驱动程序读取文本,Parquet,JSON,Hive表和来自关系数据库的数据。请注意,Spark可以自动处理压缩的数据集(如Gzip压缩数据集)。
从文件读取的数据表示为MapPartitionsRDD,而不是像当我们.paralellize(…)一个集合的数据一样表示为ParallelCollectionRDD。

1.2 Schema

RDD是无模式的数据结构(不像DataFrames)。因此,在使用RDD时,并行化数据集对于Spark来说是完美的。

>>> data_heterogenous = sc.parallelize([('Ferrari','fast'),{'Porsche':100000},['Spain','visited',4504]]).collect()

所以,我们可以混合几乎任何东西:一个元组,一个字典,或一个列表。
一旦你.collect()数据集(即,运行一个动作将其返回给驱动程序),你可以像在Python中通常那样访问对象中的数据:

>>> data_heterogenous[1]['Porsche']
100000

.collect()方法将RDD的所有元素返回到驱动程序,并将其作为列表序列化。

1.3 读取文件

从文本文件读取时,文件中的每一行形成RDD的一个元素。 可以创建一个元素列表,每行代表一个值列表。

>>> data_from_file.take(1)

[u'                   1                                          2101  M1087 432311  4M4                2014U7CN                                    I64 238 070   24 0111I64                                                                                                                                                                           01 I64                                                                                                  01  11                                 100 601']

1.4 Lambda表达式
1.4.1 Transformations

  • .map(…)

该方法应用于RDD的每个元素。

In [1]:
data_2014_2 = data_from_file_conv.map(lambda row: (row[16], int(row[16])))
data_2014_2.take(10)

Out[2]:
[('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('2014', 2014),
 ('-99', -99)]


  • .filter(…)

允许选择符合指定条件的数据集元素。

data_filtered = data_from_file_conv.filter(lambda row: row[5] == 'F' and row[21] == '0')
data_filtered.count()

  • .flatMap(…)
    与map()的工作方式类似,但返回的是平铺的结果而不是列表。
In [3]:
data_2014_flat = data_from_file_conv.flatMap(lambda row: (row[16], int(row[16]) + 1))
data_2014_flat.take(10)

Out[4]:
['2014', 2015, '2014', 2015, '2014', 2015, '2014', 2015, '2014', 2015]

  • .distinct()

此方法返回指定列中不同值的列表。


In [5]:
distinct_gender = data_from_file_conv.map(lambda row: row[5]).distinct().collect()
distinct_gender

Out[6]:
['-99', 'M', 'F']


  • .sample(…)

该方法返回数据集中的随机样本。


In [7]:
fraction = 0.1
data_sample = data_from_file_conv.sample(False, fraction, 666)

data_sample.take(1)

Out[8]:
[array(['1', '  ', '5', '1', '01', 'F', '1', '082', ' ', '42', '22', '10',
        '  ', '4', 'W', '5', '2014', 'U', '7', 'C', 'N', ' ', ' ', 'I251',
        '215', '063', '   ', '21', '02', '11I350 ', '21I251 ', '       ',
        '       ', '       ', '       ', '       ', '       ', '       ',
        '       ', '       ', '       ', '       ', '       ', '       ',
        '       ', '       ', '       ', '       ', '       ', '02',
        'I251 ', 'I350 ', '     ', '     ', '     ', '     ', '     ',
        '     ', '     ', '     ', '     ', '     ', '     ', '     ',
        '     ', '     ', '     ', '     ', '     ', '     ', '28', ' ',
        ' ', '2', '4', '100', '8'], 
       dtype='<U40')]


  • .leftOuterJoin(…)

左外连接就像SQL一样,根据两个数据集中的值加入两个RDD,并从左RDD中返回从右侧追加两个RDD匹配的记录。

>>> rd1 = sc.parallelize([('a',1),('b',4),('c',10)])
>>> rd2 = sc.parallelize([('a',4),('a',1),('b','6'),('d',15)])
>>> rd3 = rd1.leftOuterJoin(rd2)
>>> print rd3.take(5)
[('a', (1, 4)), ('a', (1, 1)), ('c', (10, None)), ('b', (4, '6'))] 

如果我们使用.join(…)方法,那么当这两个值在这两个RDD之间相交时,我们只能得到’a’和’b’的值。

>>> rd4 = rd1.join(rd2)
>>> print rd4.collect()
[('a', (1, 4)), ('a', (1, 1)), ('b', (4, '6'))]

另一个有用的方法是.intersection(…),它返回两个RDD中相同的记录。

>>> rd5 = rd1.intersection(rd2)
>>> print rd5.collect()
[('a', 1)]

该方法从单个数据分区返回n个最高行。


In [9]:
data_first = data_from_file_conv.take(1)
data_first

Out[10]:
[array(['1', '  ', '2', '1', '01', 'M', '1', '087', ' ', '43', '23', '11',
        '  ', '4', 'M', '4', '2014', 'U', '7', 'C', 'N', ' ', ' ', 'I64 ',
        '238', '070', '   ', '24', '01', '11I64  ', '       ', '       ',
        '       ', '       ', '       ', '       ', '       ', '       ',
        '       ', '       ', '       ', '       ', '       ', '       ',
        '       ', '       ', '       ', '       ', '       ', '01',
        'I64  ', '     ', '     ', '     ', '     ', '     ', '     ',
        '     ', '     ', '     ', '     ', '     ', '     ', '     ',
        '     ', '     ', '     ', '     ', '     ', '     ', '01', ' ',
        ' ', '1', '1', '100', '6'], 
       dtype='<U40')]


  • .reduce(…)
>>> rd1.map(lambda row: row[1]).reduce(lambda x,y:x+y)
15

  • .reduceByKey(…)
>>> data_key = sc.parallelize([('a', 4),('b', 3),('c', 2),('a', 8),('d', 2),('b', 1),('d', 3)],4)
>>> data_key.reduceByKey(lambda x, y: x + y).collect()
[('b', 4), ('c', 2), ('a', 12), ('d', 5)]
  • .count()

统计RDD中元素的数量。

>>> data_reduce.count()
6
  • .countByKey()

如果你的数据集是键值的形式,则可以使用.countByKey()方法获取不同键的数量。

>>> data_key.countByKey().items()
[('a', 2), ('b', 2), ('d', 2), ('c', 1)]
  • .saveAsTextFile(…)

将RDD保存到文本文件:每个分区保存到一个单独的文件。

>>> data_key.saveAsTextFile('/Users/drabast/Documents/PySpark_Data/data_key.txt')
  • .foreach(…)

一种将函数应用同到RDD每个元素的迭代法。

def f(x): 
    print(x)

data_key.foreach(f)
发布了94 篇原创文章 · 获赞 110 · 访问量 5024

猜你喜欢

转载自blog.csdn.net/beautiful_huang/article/details/104198915