我有一个PySpark应用程序,该应用程序需要从Azure blob存储帐户读取文件,该文件每5分钟以以下格式将文件分区到一个文件夹中:
\Root\yyyy\mm\dd\HH\MM\files.csv
我有一个每小时运行一次的进程,并且想要处理自上次运行以来的所有文件(如果错过了运行,则可能会超过一个小时)。我管理了一个高水位标记,告诉我上次处理文件夹的时间。
在文件内部还有一个datetime字段,该字段与路径datetime匹配(第二个更详细)。
请注意,我无法将文件夹结构更改为Year = yyyy \ month = mm等的Sparks首选分区方法。
我已经编写了此函数:
from datetime import datetime
def folderDateTimeRange(startDateTime, endDateTime, levels=5):
if startDateTime.year != endDateTime.year:
return '/{*}' * levels
elif startDateTime.month != endDateTime.month:
return datetime.strftime(startDateTime, '%Y') + '/{*}' * (levels - 1)
elif startDateTime.day != endDateTime.day:
return datetime.strftime(startDateTime, '%Y/%m') + '/{*}' * (levels - 2)
elif startDateTime.hour != endDateTime.hour:
return datetime.strftime(startDateTime, '%Y/%m/%d') + '/{*}' * (levels - 3)
else:
return ""
在大多数情况下,这会限制读取的文件夹数量。我仍然需要过滤以与函数相同的开始和结束时间读取数据的方法,因为第二天的23:00至01:00会在小时和小时部分返回{*}-因此,我认为可以更有效率。
在最糟糕的示例中,您传入start = 2018-12-31 22:00:00和end = 2019-01-01 01:00:00-这将导致读取所有年份的所有数据。
我对glob的了解有限-但是可以传递范围而不是{*}吗?
答案 0 :(得分:1)
是的,您可以使用花括号返回项目列表,也可以使用正则表达式。
在此处检查:Read range of files in pySpark和此处:pyspark select subset of files using regex/glob from s3(我不确定Azure和S3有多少区别,但我的假设是PySpark可以将其抽象化;如果我错了,请纠正我。)< / p>
您还可以通过生成一些路径并发送它们,而不是仅发送一条路径来最大程度地减少读取文件的“浪费”(这可以确保您在读取两年数据时不会有相同的陷阱。一年到下一年。)
为了娱乐起见,我在底部编写了一些测试内容的代码,您可能可以返回这些列表并获得所需的内容:
from datetime import datetime as dt
from datetime import timedelta
from collections import defaultdict
# \Root\yyyy\mm\dd\HH\MM\files.csv
def folderDateTimeRange(start, end, levels=5):
start_iter = start
paths = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(list))))
while start_iter < end:
paths[start_iter.year][start_iter.month][start_iter.day][start_iter.hour].append(start_iter.minute)
start_iter += timedelta(minutes=5)
ret_paths = []
for year, v1 in paths.items():
path = '{}\\'.format(year)
for month, v2 in v1.items():
path += '{}\\'.format(month)
for day, v3 in v2.items():
path += '{}\\'.format(day)
path += '{{{}}}\\{{*}}'.format(','.join([str(_) for _ in v3.keys()]))
ret_paths.append(path)
return ret_paths
def test(a, b):
res = folderDateTimeRange(a, b)
for r in res:
print(r)
print('---')
test(dt(2018, 1, 1), dt(2018, 1, 2))
test(dt(2018, 12, 31), dt(2019, 1, 2))