Python 读取\yyyy\mm\dd\HH\mm\范围内的文件

Python 读取\yyyy\mm\dd\HH\mm\范围内的文件,python,pyspark,azure-databricks,Python,Pyspark,Azure Databricks,我有一个PySpark应用程序,它需要从Azure blob存储帐户读取文件,在该帐户中,文件每5分钟以以下格式分区到文件夹中: \Root\yyyy\mm\dd\HH\MM\files.csv 我有一个每小时运行一次的进程,希望处理自上次运行以来的所有文件(如果错过一次运行,可能会超过一个小时)。我管理一个高水位线,它告诉我上次处理文件夹的时间 在文件中还有一个datetime字段,它与路径datetime相匹配(第二个字段有更多细节) 请注意,我无法将文件夹结构更改为年=yyyy\mont

我有一个PySpark应用程序,它需要从Azure blob存储帐户读取文件,在该帐户中,文件每5分钟以以下格式分区到文件夹中:

\Root\yyyy\mm\dd\HH\MM\files.csv
我有一个每小时运行一次的进程,希望处理自上次运行以来的所有文件(如果错过一次运行,可能会超过一个小时)。我管理一个高水位线,它告诉我上次处理文件夹的时间

在文件中还有一个datetime字段,它与路径datetime相匹配(第二个字段有更多细节)

请注意,我无法将文件夹结构更改为年=yyyy\month=mm等的首选分区方法

我编写了这个函数:

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-这将导致读取所有年份的所有数据


我对globs的了解是有限的,但是是否可以传递一个范围而不是{*}?

是的,可以使用大括号返回项目列表,也可以使用正则表达式

检查这里:这里:(我不确定Azure和S3有多大不同,但我的假设是PySpark可以将其抽象出来;如果我错了,请纠正我。)

您还可以通过生成几个路径并发送它们而不是只发送一个路径来最大限度地减少读取文件的“浪费”(这样可以确保在您从一年跨到下一年时,不会出现读取两年数据的相同陷阱。)

为了好玩,我在底部编写了一段带有一些测试内容的小代码,您可能可以返回这些列表并得到您想要的:

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))
从datetime导入datetime作为dt
从日期时间导入时间增量
从集合导入defaultdict
#\Root\yyy\mm\dd\HH\mm\files.csv
def FolderDateTime范围(开始、结束、级别=5):
启动=启动
path=defaultdict(lambda:defaultdict(lambda:defaultdict(lambda:defaultdict(list)))
当开始时<结束时:
路径[start\u iter.year][start\u iter.month][start\u iter.day][start\u iter.hour]。追加(start\u iter.minute)
启动时间+=时间增量(分钟=5)
ret_路径=[]
对于年份,路径中的v1.items():
路径=“{}\\”.格式(年)
对于月份,v1.items()中的v2:
path+='{}\\'.格式(月)
对于天,v2.items()中的v3:
路径+='{}\\'.格式(天)
path+='{{{}}\\{{*}'。格式(','.join([str(u)表示v3.keys()中的u]))
ret_path.append(路径)
返回ret_路径
def测试(a、b):
res=folderDateTimeRange(a,b)
对于r in res:
印刷品(r)
打印('--')
测试(dt(2018,1,1),dt(2018,1,2))
测试(dt(2018,12,31),dt(2019,1,2))

os.walk在这种情况下可能比glob更好。非常感谢您的努力。我做了一点小小的调整,将日/月/小时的格式设置为零填充。但逻辑依然存在。由于某些原因,我不能在几个小时内奖励奖金,但我会在以后奖励。谢谢