跳到主要内容

时间维度查询条件的执行

在实时查询采集后的指标数据功能中,是支持多种维度的,首先分为两大类:

  • 视频分类的维度:一级分类、二级分类、视频本身
  • 时间分类的维度:天、周、月、年

这两种类型维度的可以随意的相互搭配,比如:

  • 一级分类下的天查询
  • 一级分类下的月查询
  • 二级分类下的天查询
  • 二级分类下的月查询
  • ... ...

都是可以支持的,怎么搭配都是可以的,而这些搭配调用的都是同一套执行的方法流程,也就是说此查询指标数据方法的扩展性是非常高的!

查询时间范围

在查询指标数据时,有个非常重要的查询条件,当选择了天、周、月、年的维度后,就会相应对应维度下的时间范围

按天查询

按周查询

按月查询

按年查询

API入口

@Operation(summary  = "查询时间范围数据")
@PostMapping(value = "/date/range/query")
public ApiResponse<List<DateRangeQueryVo>> dateRangeQuery(@Valid @RequestBody DataTypeQueryDto dataTypeQueryDto) {
return ApiResponse.ok(collectService.dateRangeQuery(dataTypeQueryDto));
}
public List<DateRangeQueryVo> dateRangeQuery(DataTypeQueryDto dataTypeQueryDto) {
QueryDateTimeHandler queryDateTimeHandler = Optional.ofNullable(queryDateTimeHandlerContext.getQueryDateHandler(
dataTypeQueryDto.getDateType())).orElseThrow(() -> new DockDataCenterFrameException(BaseCode.DATE_TYPE_NOT_EXIST));
return queryDateTimeHandler.assembleDateTime();
}

这个结构依然是熟悉的策略模式,将天、周、月、年的时间维度划分成了不同的策略

时间策略的定义

首先要定义时间策略的行为,包括:组装日志时间、日期类型

public interface QueryDateTimeHandler {
/**
* 组装日期时间
* @return 日期范围查询视图对象列表
*/
List<DateRangeQueryVo> assembleDateTime();

/**
* 日期类型
* @return 日期类型整数
*/
Integer dateType();
}

时间策略的上下文

依旧要有上下文容器,将所有QueryDateTimeHandler的实现策略,放到容器中

@Component
public class QueryDateTimeHandlerContext {

@Autowired
private List<QueryDateTimeHandler> queryDateTimeHandlerList;

private Map<Integer, QueryDateTimeHandler> queryDateHandlerMap = new HashMap<>();

@PostConstruct
public void init(){
queryDateHandlerMap = queryDateTimeHandlerList.stream().collect(Collectors.toMap(
QueryDateTimeHandler::dateType,
handler -> handler,
(existing, replacement) -> existing));
}

public QueryDateTimeHandler getQueryDateHandler(Integer dateType) {
return queryDateHandlerMap.get(dateType);
}
}

利用了Spring的加载bean的方式,当服务启动后,会执行Spring中的@PostConstruct修饰的方法init,获取所有QueryDateTimeHandler类型的queryDateTimeHandlerList集合

接着将此集合转成queryDateHandlerMap也就是Map结构,key: 时间类型, value: 时间策略处理器

提供了getQueryDateHandler能够根据dateType日期类型从queryDateHandlerMap获取具体的时间查询实现策略

QueryDateTimeHandler的实现有:

  • QueryDayDateTimeHandler: 查询按天的时间处理器
  • QueryWeekDateTimeHandler: 查询按周的时间处理器
  • QueryMonthDateTimeHandler: 查询按月的时间处理器
  • QueryYearDateTimeHandler: 查询按年的时间处理器

查询按天的时间处理器

@Component
public class QueryDayDateTimeHandler implements QueryDateTimeHandler {

private static final Integer DAY_SIZE = 30;

@Override
public List<DateRangeQueryVo> assembleDateTime() {
List<DateRangeQueryVo> dateRangeQueryVoList = new ArrayList<>();
Date yesterdayDate = DateUtils.addDay(DateUtils.now(), -1);
Date start = new Date(0L);
Date tempDate = yesterdayDate;
for (int i = 0; i < DAY_SIZE; i++) {
DateRangeQueryVo dateRangeQueryVo = new DateRangeQueryVo();
String startDate = DateUtils.format(tempDate, DateUtils.FORMAT_DATE);
String endDate = DateUtils.format(tempDate, DateUtils.FORMAT_DATE);
dateRangeQueryVo.setStartDate(startDate);
dateRangeQueryVo.setEndDate(endDate);
dateRangeQueryVo.setRangeDateName(startDate + " ~ " + endDate);
dateRangeQueryVo.setDateType(DateType.DAY.getCode());
dateRangeQueryVoList.add(dateRangeQueryVo);
// 如果当前时间超出最小时间限制退出循环
if(tempDate.before(start)) {
break;
}
// 得到下一个要处理的时间(得到向前的一天,i + 1 是为了每次是根据 yesterdayDate 得到向前的天数
tempDate = DateUtils.obtainBeforeDate(yesterdayDate, i + 1);
}
return dateRangeQueryVoList;
}

@Override
public Integer dateType() {
return DateType.DAY.getCode();
}
}

方法意图

  • 构造“按天”维度的查询时间段清单:从“昨天”开始,最多向前回溯 DAY_SIZE(30)天,每天一条。
  • 每条时间段是单天区间:startDate == endDate,并带有展示名 startDate ~ endDate 和日期类型标记为“天”。

执行流程分解