时间维度查询条件的执行
在实时查询采集后的指标数据功能中,是支持多种维度的,首先分为两大类:
- 视频分类的维度:一级分类、二级分类、视频本身
- 时间分类的维度:天、周、月、年
这两种类型维度的可以随意的相互搭配,比如:
- 一级分类下的天查询
- 一级分类下的月查询
- 二级分类下的天查询
- 二级分类下的月查询
- ... ...
都是可以支持的,怎么搭配都是可以的,而这些搭配调用的都是同一套执行的方法流程,也就是说此查询指标数据方法的扩展性是非常高的!
查询时间范围
在查询指标数据时,有个非常重要的查询条件,当选择了天、周、月、年的维度后,就会相应对应维度下的时间范围
按天查询
按周查询
按月查询
按年查询
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
和日期类型标记为“天”。