我有一个文本文件(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 等
答案 0 :(得分:2)
在another answer中提到,dateutil.parser.parse
会返回datetime object,其中包含year
,month
和day
属性:
>>> 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等。