2024-06-16 21:31:27 +08:00
|
|
|
|
package com.example.snailjob.job;
|
|
|
|
|
|
2024-06-27 22:01:37 +08:00
|
|
|
|
import cn.hutool.core.util.ByteUtil;
|
2024-06-26 18:11:49 +08:00
|
|
|
|
import com.aizuda.snailjob.client.job.core.MapHandler;
|
2024-06-16 21:31:27 +08:00
|
|
|
|
import com.aizuda.snailjob.client.job.core.dto.MapArgs;
|
2024-06-21 16:33:42 +08:00
|
|
|
|
import com.aizuda.snailjob.client.job.core.dto.MergeReduceArgs;
|
2024-06-16 21:31:27 +08:00
|
|
|
|
import com.aizuda.snailjob.client.job.core.dto.ReduceArgs;
|
|
|
|
|
import com.aizuda.snailjob.client.job.core.executor.AbstractMapReduceExecutor;
|
|
|
|
|
import com.aizuda.snailjob.client.model.ExecuteResult;
|
2024-06-20 17:57:39 +08:00
|
|
|
|
import com.aizuda.snailjob.common.core.util.JsonUtil;
|
2024-06-21 16:33:42 +08:00
|
|
|
|
import com.aizuda.snailjob.common.log.SnailJobLog;
|
|
|
|
|
import com.example.snailjob.job.TestMapReduceJobExecutor.QuarterMap.SubTask;
|
2024-06-27 22:01:37 +08:00
|
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
2024-06-16 21:31:27 +08:00
|
|
|
|
import com.google.common.collect.Lists;
|
2024-06-20 17:57:39 +08:00
|
|
|
|
import lombok.AllArgsConstructor;
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
import lombok.Getter;
|
2024-06-21 16:33:42 +08:00
|
|
|
|
import lombok.NoArgsConstructor;
|
2024-06-16 21:31:27 +08:00
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
2024-06-20 17:57:39 +08:00
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Random;
|
|
|
|
|
|
2024-06-16 21:31:27 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2024-06-20 17:57:39 +08:00
|
|
|
|
* 以下是一个统计某电商公司商家的一年的营业额的计算过程
|
|
|
|
|
*
|
2024-06-16 21:31:27 +08:00
|
|
|
|
* @author: opensnail
|
|
|
|
|
* @date : 2024-06-13
|
|
|
|
|
* @since : sj_1.1.0
|
|
|
|
|
*/
|
|
|
|
|
@Component
|
|
|
|
|
public class TestMapReduceJobExecutor extends AbstractMapReduceExecutor {
|
|
|
|
|
|
|
|
|
|
@Override
|
2024-06-26 18:11:49 +08:00
|
|
|
|
public ExecuteResult doJobMapExecute(MapArgs mapArgs, MapHandler mapHandler) {
|
2024-06-20 17:57:39 +08:00
|
|
|
|
MapEnum mapEnum = MapEnum.ofMap(mapArgs.getTaskName());
|
2024-06-21 16:33:42 +08:00
|
|
|
|
if (Objects.nonNull(mapEnum) && Objects.nonNull(mapEnum.getMap())) {
|
2024-06-20 17:57:39 +08:00
|
|
|
|
Map map = mapEnum.getMap();
|
2024-06-21 16:33:42 +08:00
|
|
|
|
MapEnum nextMap = mapEnum.getNextMap();
|
|
|
|
|
String nextName = null;
|
|
|
|
|
if (Objects.nonNull(nextMap)) {
|
|
|
|
|
nextName = nextMap.name();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-26 18:11:49 +08:00
|
|
|
|
return mapHandler.doMap(map.map(mapArgs), nextName);
|
2024-06-16 21:31:27 +08:00
|
|
|
|
}
|
2024-06-20 17:57:39 +08:00
|
|
|
|
|
|
|
|
|
// 未找到map的任务,则说明当前需要进行处理
|
2024-06-27 22:01:37 +08:00
|
|
|
|
JsonNode json = JsonUtil.toJson(mapArgs.getMapResult());
|
|
|
|
|
SnailJobLog.LOCAL.info("LAST_MAP 开始执行 mapResult:{}", json);
|
2024-06-20 17:57:39 +08:00
|
|
|
|
// 获取最后一次map的信息.
|
2024-06-27 22:01:37 +08:00
|
|
|
|
SubTask subTask = JsonUtil.parseObject(json.toString(), SubTask.class);
|
2024-06-20 17:57:39 +08:00
|
|
|
|
// 此处可以统计数据或者做其他的事情
|
|
|
|
|
// 模拟统计营业额
|
|
|
|
|
int turnover = new Random().nextInt(1000000);
|
|
|
|
|
return ExecuteResult.success(turnover);
|
|
|
|
|
|
2024-06-16 21:31:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected ExecuteResult doReduceExecute(ReduceArgs reduceArgs) {
|
|
|
|
|
return ExecuteResult.success(reduceArgs.getMapResult());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2024-06-21 16:33:42 +08:00
|
|
|
|
protected ExecuteResult doMergeReduceExecute(MergeReduceArgs reduceArgs) {
|
|
|
|
|
List<?> reduces = reduceArgs.getReduces();
|
|
|
|
|
SnailJobLog.LOCAL.info("merge reduce {}", reduces);
|
|
|
|
|
return ExecuteResult.success(111);
|
2024-06-16 21:31:27 +08:00
|
|
|
|
}
|
2024-06-20 17:57:39 +08:00
|
|
|
|
|
|
|
|
|
@Getter
|
|
|
|
|
private enum MapEnum {
|
2024-06-21 16:33:42 +08:00
|
|
|
|
LAST_MAP(null, null),
|
|
|
|
|
MONTH_MAP(new QuarterMap(), LAST_MAP),
|
|
|
|
|
MAP_ROOT(new RootMap(), MONTH_MAP),
|
2024-06-20 17:57:39 +08:00
|
|
|
|
;
|
|
|
|
|
|
|
|
|
|
private final Map map;
|
2024-06-21 16:33:42 +08:00
|
|
|
|
private final MapEnum nextMap;
|
|
|
|
|
MapEnum(Map map, MapEnum nextMap) {
|
2024-06-20 17:57:39 +08:00
|
|
|
|
this.map = map;
|
2024-06-21 16:33:42 +08:00
|
|
|
|
this.nextMap = nextMap;
|
2024-06-20 17:57:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MapEnum ofMap(String taskName) {
|
|
|
|
|
for (final MapEnum value : MapEnum.values()) {
|
|
|
|
|
if (value.name().equals(taskName)) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class RootMap implements Map {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List map(MapArgs args) {
|
|
|
|
|
// 第一层按照商家ID分片
|
|
|
|
|
// 假设总共有一百万商家 每个分片处理10万商家
|
|
|
|
|
List<List<Long>> ranges = doSharding(1L, 1000000L, 100000);
|
|
|
|
|
return ranges;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-21 16:33:42 +08:00
|
|
|
|
public static class QuarterMap implements Map {
|
2024-06-20 17:57:39 +08:00
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List map(MapArgs args) {
|
|
|
|
|
|
|
|
|
|
// 第二层按照月分片
|
|
|
|
|
// 4个季度
|
2024-06-27 22:01:37 +08:00
|
|
|
|
JsonNode json = JsonUtil.toJson(args.getMapResult());
|
2024-06-20 17:57:39 +08:00
|
|
|
|
List<SubTask> list = new ArrayList<>();
|
2024-06-27 22:01:37 +08:00
|
|
|
|
for (JsonNode jsonNode : json) {
|
|
|
|
|
long id = jsonNode.asLong();
|
2024-06-20 17:57:39 +08:00
|
|
|
|
for (int i = 1; i <= 4; i++) {
|
|
|
|
|
list.add(new SubTask(id, i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Data
|
|
|
|
|
@AllArgsConstructor
|
2024-06-21 16:33:42 +08:00
|
|
|
|
@NoArgsConstructor
|
2024-06-20 17:57:39 +08:00
|
|
|
|
public static class SubTask {
|
|
|
|
|
// 商家id
|
|
|
|
|
private Long id;
|
|
|
|
|
|
|
|
|
|
// 需要处理的月份
|
|
|
|
|
private Integer quarter;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface Map{
|
|
|
|
|
List<Object> map(MapArgs args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<List<Long>> doSharding(Long min, Long max, int interval) {
|
|
|
|
|
|
|
|
|
|
if (max.equals(min)) {
|
|
|
|
|
return new ArrayList<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 总数量
|
|
|
|
|
long total = max - min + 1;
|
|
|
|
|
|
|
|
|
|
// 计算分页总页数
|
|
|
|
|
Long totalPages = total / interval;
|
|
|
|
|
if (total % interval != 0) {
|
|
|
|
|
totalPages++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<List<Long>> partitions = new ArrayList<>();
|
|
|
|
|
for (Long index = 0L; index < totalPages; index++) {
|
|
|
|
|
|
|
|
|
|
// 计算起始点 因为是从min开始所以每次需要加上一个min
|
|
|
|
|
Long start = index * interval + min;
|
|
|
|
|
|
|
|
|
|
// 结算结束点 若最后一个 start + interval - 1 > max 取max
|
|
|
|
|
// 减一是保证 [start, end] 都是闭区间
|
|
|
|
|
Long end = Math.min(start + interval - 1, max);
|
|
|
|
|
partitions.add(Lists.newArrayList(start, end));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return partitions;
|
|
|
|
|
}
|
2024-06-16 21:31:27 +08:00
|
|
|
|
}
|