日期范围的通配符表示-附python、Scala代码

本文探讨大数据开发中日期范围的表示,对比MapReduce和Spark的不同处理方式。通过案例分析,提出在Spark中使用通配符避免暴力扫描的问题,并给出Python和Scala实现的递归解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文记录了将给定的日期范围用通配符表示的相关内容,欢迎与我沟通联系(zhaoliang19960421@outlook.com)
如果在使用中发现程序输入与结果不符,欢迎与我沟通

当前大数据开发中,数据通常以时间date为分区保存在hdfs中,例如 hdfs://abc/date=20220101

在主流的两大大数据开发框架MapReduce、Spark中对于单个日期数据的输入形式一样,都是直接输入对应日期的hdfs路径即可。

在跨分区读取数据时,MapReduce提供了时间的通配符表示法,例如要读取2022年1月份整月的数据,可以表示成202201*
spark相较于MR提供了类似于sql的时间范围写法

sparkSession.read.parquet(s"hdfs://abc")
	.where(s"date between $startDate and $endDate")

但是该方法仍存在不足:在read.parquet(s"hdfs://abc")实际上将该路径下的所有分区都扫描一遍,找到所有满足where条件的分区
这样做虽然并没有实际的将数据读进来,但是仍然需要暴力的扫描整个路径,以便找到满足条件的结果。如果上游数据分区特别多时,采用该方案耗时仍然很高

为了解决该问题,在spark读取路径时可以采用指定输入地址路径列表的方式来避免暴力扫描,也就是将[startDate,endDate]时间范围内的路径直接写出来,不在进行where判断,直接去读对应的时间分区。但是这样实际开发中很不方便,例如要计算2022年1月份的全部数据,需要写31个路径,即使通过写循环语句来解决仍然不够优雅。

在spark中同样支持如MR的通配符表示法,也就是用202201*来表示22年1月份的全部数据,采用这样的方式即避免了暴力扫描的耗时,也避免了写31个路径以及写循环的复杂性。

具体含义以几个case进一步解释

case1 日期范围是:20220101 20221231
解释:需要输入的是2022年一整年的数据,所以采用通配符的表达方式为2022*


case2 日期范围是 : 20210101 20210331
解释:需要输入的2021年,1月、2月、3月的全部日期,采用通配符的表示方式是 '202101*', '202102*', '202103*'

case3 日起范围是:20200104 20200302
解释:需要输入的是,从1月4号到1月底,2月整月、3月1号,3月2号的日期,采用通配符的表示方式是 ['20200104', '20200105', '20200106', '20200107', '20200108', '20200109', '2020011*', '2020012*', '2020013*', '202002*', '20200301', '20200302']
因为1月4号到1月9号,无法继续采用通配符,所以全部枚举;1月10号到1月19号、1月11号到19号、1月21号到1月29号、1月30号到1月31号,均可以用通配符。

将以上问题抽象为数学问题是,给定一个函数,输入的是2个字符串[start,end]的日期范围,输出一个字符串数组,这个字符串数组是给定日期范围的通配符表示式的最简结果

该问题采用递归的方式来解决,具体内容见python、Scala代码

def timeWindow2timeWildcard(start: str, end: str) -> list:
    """
    将给定的时间范围 [start,end] 转化成 最简的时间通配符表达式
    :param start: 开始时间,左闭
    :param end: 结束时间,右闭
    :return: list[str] 整个list的结果是时间范围的最简单的时间通配符结果
    """

    def _yyyyMM2dd(yyyy, MM):
        """
        输出给定年、月的日期
        """
        if MM in {
   1, 3, 5, 7, 8, 10, 12}:
            return 31
        if MM != 2:
            return 30
        if (yyyy % 4 == 0) and (yyyy % 100 != 0) or (yyyy % 400) == 0:
            return 29
        else:
            return 28

    def _check(yyyyMMdd):
        """
        检查日期是否合理,
        """
        date = _yyyyMM2dd(int(yyyyMMdd[:4]), int(yyyyMMdd[4:6]))
        if 1 <= int(yyyyMMdd[6:8]) <= date:
            return yyyyMMdd
        if 1 > int(yyyyMMdd[6:8]):
            return "{}01".<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值