如何使用mapreduce和pyspark

时间:2016-05-13 14:57:51

标签: datetime hadoop mapreduce pyspark

我有一个文本文件(61Gb),每行包含一个表示日期的字符串,例如Thu Dec 16 18:53:32 +0000 2010

在单个核心上迭代文件需要很长时间,因此我想使用Pyspark和Mapreduce技术快速查找某一年某一行的频率。

我认为这是一个良好的开端:

import dateutil.parser
text_file = sc.textFile('dates.txt')
date_freqs = text_file.map(lambda line: dateutil.parser.parse(line)) \
        .map(lambda date: date + 1) \
        .reduceByKey(lambda a, b: a + b)

不幸的是,我无法理解如何过滤特定年份并按键减少。关键是这一天。

示例输出:

Thu Dec 16 26543

Thu 12月17日345 等

3 个答案:

答案 0 :(得分:2)

another answer中提到,dateutil.parser.parse会返回datetime object,其中包含yearmonthday属性:

>>> dt = dateutil.parser.parse('Thu Dec 16 18:53:32 +0000 2010')
>>> dt.year
2010
>>> dt.month
12
>>> dt.day
16

从这个RDD开始:

>>> rdd = sc.parallelize([
...     'Thu Oct 21 5:12:38 +0000 2010',
...     'Thu Oct 21 4:12:38 +0000 2010',
...     'Wed Sep 22 15:46:40 +0000 2010',
...     'Sun Sep 4 22:28:48 +0000 2011',
...     'Sun Sep 4 21:28:48 +0000 2011'])

以下是如何获取所有年 - 月 - 天组合的计数:

>>> from operator import attrgetter
>>> counts = rdd.map(dateutil.parser.parse).map(
...     attrgetter('year', 'month', 'day')).countByValue()
>>> counts
defaultdict(<type 'int'>, {(2010, 9, 22): 1, (2010, 10, 21): 2, (2011, 9, 4): 2})

获得所需的输出:

>>> for k, v in counts.iteritems():
...     print datetime.datetime(*k).strftime('%a %b %y'), v
...
Wed Sep 10 1
Thu Oct 10 2
Sun Sep 11 2

如果您只想要某一年的计数,您可以在计算之前过滤RDD:

>>> counts = rdd.map(dateutil.parser.parse).map(
...    attrgetter('year', 'month', 'day')).filter(
...    lambda (y, m, d): y == 2010).countByValue()
>>> counts
defaultdict(<type 'int'>, {(2010, 9, 22): 1, (2010, 10, 21): 2})

答案 1 :(得分:1)

Something along the lines of this might be a good start:

import dateutil.parser
text_file = sc.textFile('dates.txt')
date_freqs = text_file.map(lambda line: dateutil.parser.parse(line))
    .keyBy((_.year, _.month, _.day)) // somehow get the year, month, day to key by
    .countByKey()

答案 2 :(得分:0)

我应该补充一点,dateutil在Python中不是标准的。如果您的群集上没有sudo权限,则可能会出现问题。作为一个解决方案,我想建议使用datetime:

import datetime
def parse_line(d):
    f = "%a %b %d %X %Y"
    date_list = d.split()
    date = date_list[:4]
    date.append(date_list[5])
    date = ' '.join(date)
    return datetime.datetime.strptime(date, f)

counts = rdd.map(parse_line)\
    .map(attrgetter('year', 'month', 'day'))\
    .filter(lambda (y, m, d): y == 2015)\
    .countByValue()

我对更好的解决方案感兴趣:Parquet,Row / Columns等。