2026.1.13提交最终版(2)

This commit is contained in:
wangran
2026-01-13 20:22:33 +08:00
parent 714bd99b06
commit 006c9c841e
2 changed files with 0 additions and 820 deletions

View File

@@ -381,358 +381,6 @@ public class AppTrafficController {
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}
/**
* 统计各手机网络质量使用情况,支持按运营商、网络制式、流量范围和日期范围筛选
* @param request 查询请求参数,所有字段均为可选
* @return 手机网络质量使用情况统计列表,按总流量降序排列
*/
@PostMapping("/appTraffic/phoneQuality")
public List<com.bigdata.dto.PhoneQualityUsageDTO> getPhoneQualityUsage(
@RequestBody(required = false) com.bigdata.dto.PhoneQualityUsageRequest request) {
// 如果请求体为空,创建默认请求对象
if (request == null) {
request = new com.bigdata.dto.PhoneQualityUsageRequest();
}
String operator = null;
String networkType = null;
Double minUploadTraffic = null;
Double maxUploadTraffic = null;
Double minDownloadTraffic = null;
Double maxDownloadTraffic = null;
String startDate = null;
String endDate = null;
// 处理运营商参数ALL 或不传表示查询所有
if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) {
String op = request.getOperator().trim().toUpperCase();
if (!"ALL".equals(op)) {
operator = op;
}
}
// 处理网络制式
if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) {
networkType = request.getNetworkType().trim();
}
// 处理流量范围
if (request.getMinUploadTraffic() != null) {
minUploadTraffic = request.getMinUploadTraffic();
}
if (request.getMaxUploadTraffic() != null) {
maxUploadTraffic = request.getMaxUploadTraffic();
}
if (request.getMinDownloadTraffic() != null) {
minDownloadTraffic = request.getMinDownloadTraffic();
}
if (request.getMaxDownloadTraffic() != null) {
maxDownloadTraffic = request.getMaxDownloadTraffic();
}
// 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd
if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) {
startDate = request.getStartDate().trim().replace("-", "");
}
if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) {
endDate = request.getEndDate().trim().replace("-", "");
}
// 查询手机网络质量使用情况统计
List<com.bigdata.dto.PhoneQualityUsageDTO> result =
appTrafficService.getPhoneQualityUsage(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
// 打印到控制台
System.out.println("====== app_traffic phone quality statistics ======");
System.out.println("Operator: " + (operator != null ? operator : "ALL"));
System.out.println("Network Type: " + (networkType != null ? networkType : "ALL"));
System.out.println("Upload Traffic Range: " +
(minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " +
(maxUploadTraffic != null ? maxUploadTraffic : "MAX"));
System.out.println("Download Traffic Range: " +
(minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " +
(maxDownloadTraffic != null ? maxDownloadTraffic : "MAX"));
System.out.println("Start Date: " + (startDate != null ? startDate : "ALL"));
System.out.println("End Date: " + (endDate != null ? endDate : "ALL"));
System.out.println("Total phones: " + result.size());
for (com.bigdata.dto.PhoneQualityUsageDTO dto : result) {
System.out.println("Phone: " + dto.getPhoneModel() +
", OS: " + dto.getOs() +
", OS Version: " + dto.getOsVersion() +
", Operator: " + dto.getOperator() +
", Total Traffic: " + dto.getTotalTraffic() +
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}
/**
* 统计各手机流量占比,支持按运营商、网络制式、流量范围和日期范围筛选
* @param request 查询请求参数,所有字段均为可选
* @return 手机流量占比统计列表,按总流量降序排列
*/
@PostMapping("/appTraffic/phoneTrafficRatio")
public List<com.bigdata.dto.PhoneTrafficRatioDTO> getPhoneTrafficRatio(
@RequestBody(required = false) AppTrafficQueryRequest request) {
// 如果请求体为空,创建默认请求对象
if (request == null) {
request = new AppTrafficQueryRequest();
}
String operator = null;
String networkType = null;
Double minUploadTraffic = null;
Double maxUploadTraffic = null;
Double minDownloadTraffic = null;
Double maxDownloadTraffic = null;
String startDate = null;
String endDate = null;
// 处理运营商参数ALL 或不传表示查询所有
if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) {
String op = request.getOperator().trim().toUpperCase();
if (!"ALL".equals(op)) {
operator = op;
}
}
// 处理网络制式
if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) {
networkType = request.getNetworkType().trim();
}
// 处理流量范围
if (request.getMinUploadTraffic() != null) {
minUploadTraffic = request.getMinUploadTraffic();
}
if (request.getMaxUploadTraffic() != null) {
maxUploadTraffic = request.getMaxUploadTraffic();
}
if (request.getMinDownloadTraffic() != null) {
minDownloadTraffic = request.getMinDownloadTraffic();
}
if (request.getMaxDownloadTraffic() != null) {
maxDownloadTraffic = request.getMaxDownloadTraffic();
}
// 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd
if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) {
startDate = request.getStartDate().trim().replace("-", "");
}
if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) {
endDate = request.getEndDate().trim().replace("-", "");
}
// 查询手机流量占比统计
List<com.bigdata.dto.PhoneTrafficRatioDTO> result =
appTrafficService.getPhoneTrafficRatio(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
// 打印到控制台
System.out.println("====== app_traffic phone traffic ratio statistics ======");
System.out.println("Operator: " + (operator != null ? operator : "ALL"));
System.out.println("Network Type: " + (networkType != null ? networkType : "ALL"));
System.out.println("Upload Traffic Range: " +
(minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " +
(maxUploadTraffic != null ? maxUploadTraffic : "MAX"));
System.out.println("Download Traffic Range: " +
(minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " +
(maxDownloadTraffic != null ? maxDownloadTraffic : "MAX"));
System.out.println("Start Date: " + (startDate != null ? startDate : "ALL"));
System.out.println("End Date: " + (endDate != null ? endDate : "ALL"));
System.out.println("Total phones: " + result.size());
for (com.bigdata.dto.PhoneTrafficRatioDTO dto : result) {
System.out.println("Phone: " + dto.getPhoneModel() +
", OS: " + dto.getOs() +
", OS Version: " + dto.getOsVersion() +
", Operator: " + dto.getOperator() +
", Total Traffic: " + dto.getTotalTraffic() +
", Ratio: " + dto.getTrafficRatio() + "%" +
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}
/**
* 统计各操作系统流量占比,支持按运营商、网络制式、流量范围和日期范围筛选
* @param request 查询请求参数,所有字段均为可选
* @return 操作系统流量占比统计列表,按总流量降序排列
*/
@PostMapping("/appTraffic/osTrafficRatio")
public List<com.bigdata.dto.OsTrafficRatioDTO> getOsTrafficRatio(
@RequestBody(required = false) AppTrafficQueryRequest request) {
// 如果请求体为空,创建默认请求对象
if (request == null) {
request = new AppTrafficQueryRequest();
}
String operator = null;
String networkType = null;
Double minUploadTraffic = null;
Double maxUploadTraffic = null;
Double minDownloadTraffic = null;
Double maxDownloadTraffic = null;
String startDate = null;
String endDate = null;
// 处理运营商参数ALL 或不传表示查询所有
if (request.getOperator() != null && !request.getOperator().trim().isEmpty()) {
String op = request.getOperator().trim().toUpperCase();
if (!"ALL".equals(op)) {
operator = op;
}
}
// 处理网络制式
if (request.getNetworkType() != null && !request.getNetworkType().trim().isEmpty()) {
networkType = request.getNetworkType().trim();
}
// 处理流量范围
if (request.getMinUploadTraffic() != null) {
minUploadTraffic = request.getMinUploadTraffic();
}
if (request.getMaxUploadTraffic() != null) {
maxUploadTraffic = request.getMaxUploadTraffic();
}
if (request.getMinDownloadTraffic() != null) {
minDownloadTraffic = request.getMinDownloadTraffic();
}
if (request.getMaxDownloadTraffic() != null) {
maxDownloadTraffic = request.getMaxDownloadTraffic();
}
// 处理日期范围:将 yyyy-MM-dd 格式转换为 yyyyMMdd
if (request.getStartDate() != null && !request.getStartDate().trim().isEmpty()) {
startDate = request.getStartDate().trim().replace("-", "");
}
if (request.getEndDate() != null && !request.getEndDate().trim().isEmpty()) {
endDate = request.getEndDate().trim().replace("-", "");
}
// 查询操作系统流量占比统计
List<com.bigdata.dto.OsTrafficRatioDTO> result =
appTrafficService.getOsTrafficRatio(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
// 打印到控制台
System.out.println("====== app_traffic os traffic ratio statistics ======");
System.out.println("Operator: " + (operator != null ? operator : "ALL"));
System.out.println("Network Type: " + (networkType != null ? networkType : "ALL"));
System.out.println("Upload Traffic Range: " +
(minUploadTraffic != null ? minUploadTraffic : "MIN") + " ~ " +
(maxUploadTraffic != null ? maxUploadTraffic : "MAX"));
System.out.println("Download Traffic Range: " +
(minDownloadTraffic != null ? minDownloadTraffic : "MIN") + " ~ " +
(maxDownloadTraffic != null ? maxDownloadTraffic : "MAX"));
System.out.println("Start Date: " + (startDate != null ? startDate : "ALL"));
System.out.println("End Date: " + (endDate != null ? endDate : "ALL"));
System.out.println("Total OS: " + result.size());
for (com.bigdata.dto.OsTrafficRatioDTO dto : result) {
System.out.println("OS: " + dto.getOsName() +
", OS: " + dto.getOs() +
", OS Version: " + dto.getOsVersion() +
", Operator: " + dto.getOperator() +
", Total Traffic: " + dto.getTotalTraffic() +
", Ratio: " + dto.getTrafficRatio() + "%" +
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}
/**
* 统计可视区域内每个区域的流量top1 热门手机
* 将可视区域划分为300个矩形20x15返回每个区域的top1 热门手机
* @param request 查询请求参数,包含运营商、网络制式、流量范围、日期范围、可视区域范围等
* @return 各区域的top1 热门手机统计列表
*/
@PostMapping("/appTraffic/phoneRegionTop")
public List<com.bigdata.dto.PhoneTrafficRegionTopDTO> getPhoneRegionTop(
@RequestBody(required = false) com.bigdata.dto.PhoneTrafficRegionTopRequest request) {
// 如果请求体为空,创建默认请求对象
if (request == null) {
request = new com.bigdata.dto.PhoneTrafficRegionTopRequest();
}
// 查询区域top1 热门手机
List<com.bigdata.dto.PhoneTrafficRegionTopDTO> result = appTrafficService.getPhoneRegionTop(request);
// 打印到控制台
System.out.println("====== app_traffic phone region top1 statistics ======");
System.out.println("Operator: " + (request.getOperator() != null ? request.getOperator() : "ALL"));
System.out.println("Network Type: " + (request.getNetworkType() != null ? request.getNetworkType() : "ALL"));
System.out.println("Start Date: " + (request.getStartDate() != null ? request.getStartDate() : "ALL"));
System.out.println("End Date: " + (request.getEndDate() != null ? request.getEndDate() : "ALL"));
System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " +
(request.getGridRows() * request.getGridCols()) + " regions");
System.out.println("Total regions with data: " + result.size());
for (com.bigdata.dto.PhoneTrafficRegionTopDTO dto : result) {
System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() +
"] (" + dto.getCenterLat() + "," + dto.getCenterLon() +
") Top1: " + dto.getPhoneModel() +
" (OS: " + dto.getOs() + ", Version: " + dto.getOsVersion() + ")" +
", Traffic: " + dto.getTotalTraffic() +
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}
/**
* 统计可视区域内每个区域的流量top1 手机OS
* 将可视区域划分为300个矩形20x15返回每个区域的top1 手机OS
* @param request 查询请求参数,包含运营商、网络制式、流量范围、日期范围、可视区域范围等
* @return 各区域的top1 手机OS统计列表
*/
@PostMapping("/appTraffic/osRegionTop")
public List<com.bigdata.dto.OsTrafficRegionTopDTO> getOsRegionTop(
@RequestBody(required = false) com.bigdata.dto.OsTrafficRegionTopRequest request) {
// 如果请求体为空,创建默认请求对象
if (request == null) {
request = new com.bigdata.dto.OsTrafficRegionTopRequest();
}
// 查询区域top1 手机OS
List<com.bigdata.dto.OsTrafficRegionTopDTO> result = appTrafficService.getOsRegionTop(request);
// 打印到控制台
System.out.println("====== app_traffic OS region top1 statistics ======");
System.out.println("Operator: " + (request.getOperator() != null ? request.getOperator() : "ALL"));
System.out.println("Network Type: " + (request.getNetworkType() != null ? request.getNetworkType() : "ALL"));
System.out.println("Start Date: " + (request.getStartDate() != null ? request.getStartDate() : "ALL"));
System.out.println("End Date: " + (request.getEndDate() != null ? request.getEndDate() : "ALL"));
System.out.println("Grid: " + request.getGridRows() + "x" + request.getGridCols() + " = " +
(request.getGridRows() * request.getGridCols()) + " regions");
System.out.println("Total regions with data: " + result.size());
for (com.bigdata.dto.OsTrafficRegionTopDTO dto : result) {
System.out.println("Region [" + dto.getRowIndex() + "," + dto.getColIndex() +
"] (" + dto.getCenterLat() + "," + dto.getCenterLon() +
") Top1: " + dto.getOsName() +
", Traffic: " + dto.getTotalTraffic() +
", Records: " + dto.getRecordCount());
}
System.out.println("================================================");
return result;
}

View File

@@ -147,95 +147,6 @@ public class AppTrafficServiceImpl implements AppTrafficService {
startDate, endDate);
}
@Override
public List<com.bigdata.dto.PhoneTrafficRatioDTO> getPhoneTrafficRatio(
String operator,
String networkType,
Double minUploadTraffic,
Double maxUploadTraffic,
Double minDownloadTraffic,
Double maxDownloadTraffic,
String startDate,
String endDate) {
List<com.bigdata.dto.PhoneTrafficRatioDTO> result = appTrafficMapper.selectPhoneTrafficRatio(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
// 计算总流量,用于计算占比
double totalTrafficSum = result.stream()
.mapToDouble(dto -> dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0)
.sum();
// 计算每个手机的流量占比
if (totalTrafficSum > 0) {
for (com.bigdata.dto.PhoneTrafficRatioDTO dto : result) {
if (dto.getTotalTraffic() != null && dto.getTotalTraffic() > 0) {
double ratio = (dto.getTotalTraffic() / totalTrafficSum) * 100.0;
dto.setTrafficRatio(Math.round(ratio * 100.0) / 100.0); // 保留2位小数
} else {
dto.setTrafficRatio(0.0);
}
}
}
return result;
}
@Override
public List<com.bigdata.dto.OsTrafficRatioDTO> getOsTrafficRatio(
String operator,
String networkType,
Double minUploadTraffic,
Double maxUploadTraffic,
Double minDownloadTraffic,
Double maxDownloadTraffic,
String startDate,
String endDate) {
List<com.bigdata.dto.OsTrafficRatioDTO> result = appTrafficMapper.selectOsTrafficRatio(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
// 计算总流量,用于计算占比
double totalTrafficSum = result.stream()
.mapToDouble(dto -> dto.getTotalTraffic() != null ? dto.getTotalTraffic() : 0.0)
.sum();
// 计算每个操作系统的流量占比
if (totalTrafficSum > 0) {
for (com.bigdata.dto.OsTrafficRatioDTO dto : result) {
if (dto.getTotalTraffic() != null && dto.getTotalTraffic() > 0) {
double ratio = (dto.getTotalTraffic() / totalTrafficSum) * 100.0;
dto.setTrafficRatio(Math.round(ratio * 100.0) / 100.0); // 保留2位小数
} else {
dto.setTrafficRatio(0.0);
}
}
}
return result;
}
@Override
public List<com.bigdata.dto.PhoneQualityUsageDTO> getPhoneQualityUsage(
String operator,
String networkType,
Double minUploadTraffic,
Double maxUploadTraffic,
Double minDownloadTraffic,
Double maxDownloadTraffic,
String startDate,
String endDate) {
return appTrafficMapper.selectPhoneQualityUsage(
operator, networkType,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
}
@Override
public List<com.bigdata.dto.PhoneTrafficRatioDTO> getPhoneTrafficRatio(
String operator,
@@ -872,385 +783,6 @@ public class AppTrafficServiceImpl implements AppTrafficService {
}
}
}
return result;
}
@Override
public List<com.bigdata.dto.PhoneTrafficRegionTopDTO> getPhoneRegionTop(com.bigdata.dto.PhoneTrafficRegionTopRequest request) {
// 1. 准备查询参数
String operator = null;
if (request.getOperator() != null && !request.getOperator().trim().isEmpty() && !"ALL".equals(request.getOperator().trim().toUpperCase())) {
operator = request.getOperator().trim().toUpperCase();
}
String networkType = request.getNetworkType();
Double minUploadTraffic = request.getMinUploadTraffic();
Double maxUploadTraffic = request.getMaxUploadTraffic();
Double minDownloadTraffic = request.getMinDownloadTraffic();
Double maxDownloadTraffic = request.getMaxDownloadTraffic();
String startDate = request.getStartDate() != null ? request.getStartDate().replace("-", "") : null;
String endDate = request.getEndDate() != null ? request.getEndDate().replace("-", "") : null;
// 2. 查询数据
List<AppTraffic> dataList = appTrafficMapper.selectByCondition(
operator, networkType, null,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
if (dataList == null || dataList.isEmpty()) {
return new ArrayList<>();
}
// 3. 确定可视区域范围
Double minLon = request.getMinLon();
Double maxLon = request.getMaxLon();
Double minLat = request.getMinLat();
Double maxLat = request.getMaxLat();
if (minLon == null || maxLon == null || minLat == null || maxLat == null) {
// 如果没有指定范围,从数据中计算
List<Double> validLons = new ArrayList<>();
List<Double> validLats = new ArrayList<>();
for (AppTraffic traffic : dataList) {
try {
if (traffic.getUserLon() != null && !traffic.getUserLon().trim().isEmpty()) {
validLons.add(Double.parseDouble(traffic.getUserLon()));
}
if (traffic.getUserLat() != null && !traffic.getUserLat().trim().isEmpty()) {
validLats.add(Double.parseDouble(traffic.getUserLat()));
}
} catch (NumberFormatException e) {
// 忽略无效的经纬度数据
}
}
// 如果没有有效的经纬度数据,返回空列表
if (validLons.isEmpty() || validLats.isEmpty()) {
return new ArrayList<>();
}
minLon = validLons.stream().mapToDouble(Double::doubleValue).min().orElse(116.0);
maxLon = validLons.stream().mapToDouble(Double::doubleValue).max().orElse(117.0);
minLat = validLats.stream().mapToDouble(Double::doubleValue).min().orElse(39.0);
maxLat = validLats.stream().mapToDouble(Double::doubleValue).max().orElse(40.0);
// 如果范围太小,扩展一点
if (maxLon - minLon < 0.001) {
double centerLon = (minLon + maxLon) / 2.0;
minLon = centerLon - 0.01;
maxLon = centerLon + 0.01;
}
if (maxLat - minLat < 0.001) {
double centerLat = (minLat + maxLat) / 2.0;
minLat = centerLat - 0.01;
maxLat = centerLat + 0.01;
}
}
// 4. 网格参数
int gridRows = request.getGridRows() != null ? request.getGridRows() : 20;
int gridCols = request.getGridCols() != null ? request.getGridCols() : 15;
// 确保范围有效
if (maxLon <= minLon || maxLat <= minLat) {
return new ArrayList<>();
}
double lonStep = (maxLon - minLon) / gridCols;
double latStep = (maxLat - minLat) / gridRows;
// 确保步长不为0
if (lonStep <= 0 || latStep <= 0) {
return new ArrayList<>();
}
// 5. 按区域分组统计(按手机型号分组)
Map<String, Map<String, Double>> regionPhoneTrafficMap = new HashMap<>();
Map<String, Long> regionRecordCountMap = new HashMap<>();
Map<String, String> phoneOsMap = new HashMap<>(); // 存储手机型号对应的OS
Map<String, String> phoneOsVersionMap = new HashMap<>(); // 存储手机型号对应的OS_ANDVERSION
for (AppTraffic traffic : dataList) {
if (traffic.getUserLon() == null || traffic.getUserLon().trim().isEmpty() ||
traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) {
continue;
}
try {
double lon = Double.parseDouble(traffic.getUserLon());
double lat = Double.parseDouble(traffic.getUserLat());
// 检查是否在可视区域内
if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) {
continue;
}
// 计算所属区域
int colIndex = Math.min((int) ((lon - minLon) / lonStep), gridCols - 1);
int rowIndex = Math.min((int) ((lat - minLat) / latStep), gridRows - 1);
String regionKey = rowIndex + "_" + colIndex;
// 构建手机型号keyOS + OS_ANDVERSION
// 注意实体类中osVersion字段对应数据库的OS_ANDVERSION列
String os = traffic.getOs() != null ? traffic.getOs() : "";
String osAndVersion = traffic.getOsVersion() != null ? traffic.getOsVersion() : "";
String phoneKey = (os.toLowerCase() + osAndVersion).trim();
if (phoneKey.isEmpty()) {
continue; // 跳过没有OS信息的记录
}
// 计算总流量
double totalTraffic = (traffic.getUploadTraffic() != null ? traffic.getUploadTraffic() : 0.0) +
(traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0);
// 累计流量
regionPhoneTrafficMap.computeIfAbsent(regionKey, k -> new HashMap<>())
.merge(phoneKey, totalTraffic, Double::sum);
regionRecordCountMap.merge(regionKey, 1L, Long::sum);
// 保存手机型号对应的OS和OS_ANDVERSION
phoneOsMap.put(phoneKey, os);
phoneOsVersionMap.put(phoneKey, osAndVersion);
} catch (NumberFormatException e) {
// 忽略无效的经纬度数据
continue;
}
}
// 6. 找出每个区域的top1 热门手机
List<com.bigdata.dto.PhoneTrafficRegionTopDTO> result = new ArrayList<>();
for (int row = 0; row < gridRows; row++) {
for (int col = 0; col < gridCols; col++) {
String regionKey = row + "_" + col;
Map<String, Double> phoneTrafficMap = regionPhoneTrafficMap.get(regionKey);
if (phoneTrafficMap == null || phoneTrafficMap.isEmpty()) {
continue; // 该区域没有数据,跳过
}
// 找出流量最大的手机
Map.Entry<String, Double> topPhone = phoneTrafficMap.entrySet().stream()
.max(Map.Entry.comparingByValue())
.orElse(null);
if (topPhone != null) {
String phoneKey = topPhone.getKey();
String os = phoneOsMap.getOrDefault(phoneKey, "");
String osVersion = phoneOsVersionMap.getOrDefault(phoneKey, "");
String phoneModel = (os.toLowerCase() + osVersion).trim();
// 计算区域中心点
double centerLon = minLon + (col + 0.5) * lonStep;
double centerLat = minLat + (row + 0.5) * latStep;
com.bigdata.dto.PhoneTrafficRegionTopDTO dto = new com.bigdata.dto.PhoneTrafficRegionTopDTO();
dto.setRowIndex(row);
dto.setColIndex(col);
dto.setCenterLon(centerLon);
dto.setCenterLat(centerLat);
dto.setPhoneModel(phoneModel);
dto.setOs(os);
dto.setOsVersion(osVersion);
dto.setTotalTraffic(topPhone.getValue());
dto.setRecordCount(regionRecordCountMap.getOrDefault(regionKey, 0L));
result.add(dto);
}
}
}
return result;
}
@Override
public List<com.bigdata.dto.OsTrafficRegionTopDTO> getOsRegionTop(com.bigdata.dto.OsTrafficRegionTopRequest request) {
// 1. 准备查询参数
String operator = null;
if (request.getOperator() != null && !request.getOperator().trim().isEmpty() && !"ALL".equals(request.getOperator().trim().toUpperCase())) {
operator = request.getOperator().trim().toUpperCase();
}
String networkType = request.getNetworkType();
Double minUploadTraffic = request.getMinUploadTraffic();
Double maxUploadTraffic = request.getMaxUploadTraffic();
Double minDownloadTraffic = request.getMinDownloadTraffic();
Double maxDownloadTraffic = request.getMaxDownloadTraffic();
String startDate = request.getStartDate() != null ? request.getStartDate().replace("-", "") : null;
String endDate = request.getEndDate() != null ? request.getEndDate().replace("-", "") : null;
// 2. 查询数据
List<AppTraffic> dataList = appTrafficMapper.selectByCondition(
operator, networkType, null,
minUploadTraffic, maxUploadTraffic,
minDownloadTraffic, maxDownloadTraffic,
startDate, endDate);
if (dataList == null || dataList.isEmpty()) {
return new ArrayList<>();
}
// 3. 确定可视区域范围
Double minLon = request.getMinLon();
Double maxLon = request.getMaxLon();
Double minLat = request.getMinLat();
Double maxLat = request.getMaxLat();
if (minLon == null || maxLon == null || minLat == null || maxLat == null) {
// 如果没有指定范围,从数据中计算
List<Double> validLons = new ArrayList<>();
List<Double> validLats = new ArrayList<>();
for (AppTraffic traffic : dataList) {
try {
if (traffic.getUserLon() != null && !traffic.getUserLon().trim().isEmpty()) {
validLons.add(Double.parseDouble(traffic.getUserLon()));
}
if (traffic.getUserLat() != null && !traffic.getUserLat().trim().isEmpty()) {
validLats.add(Double.parseDouble(traffic.getUserLat()));
}
} catch (NumberFormatException e) {
// 忽略无效的经纬度数据
}
}
// 如果没有有效的经纬度数据,返回空列表
if (validLons.isEmpty() || validLats.isEmpty()) {
return new ArrayList<>();
}
minLon = validLons.stream().mapToDouble(Double::doubleValue).min().orElse(116.0);
maxLon = validLons.stream().mapToDouble(Double::doubleValue).max().orElse(117.0);
minLat = validLats.stream().mapToDouble(Double::doubleValue).min().orElse(39.0);
maxLat = validLats.stream().mapToDouble(Double::doubleValue).max().orElse(40.0);
// 如果范围太小,扩展一点
if (maxLon - minLon < 0.001) {
double centerLon = (minLon + maxLon) / 2.0;
minLon = centerLon - 0.01;
maxLon = centerLon + 0.01;
}
if (maxLat - minLat < 0.001) {
double centerLat = (minLat + maxLat) / 2.0;
minLat = centerLat - 0.01;
maxLat = centerLat + 0.01;
}
}
// 4. 网格参数
int gridRows = request.getGridRows() != null ? request.getGridRows() : 20;
int gridCols = request.getGridCols() != null ? request.getGridCols() : 15;
// 确保范围有效
if (maxLon <= minLon || maxLat <= minLat) {
return new ArrayList<>();
}
double lonStep = (maxLon - minLon) / gridCols;
double latStep = (maxLat - minLat) / gridRows;
// 确保步长不为0
if (lonStep <= 0 || latStep <= 0) {
return new ArrayList<>();
}
// 5. 按区域分组统计按OS分组
Map<String, Map<String, Double>> regionOsTrafficMap = new HashMap<>();
Map<String, Long> regionRecordCountMap = new HashMap<>();
Map<String, String> osNameMap = new HashMap<>(); // 存储OS key对应的OS名称
for (AppTraffic traffic : dataList) {
if (traffic.getUserLon() == null || traffic.getUserLon().trim().isEmpty() ||
traffic.getUserLat() == null || traffic.getUserLat().trim().isEmpty()) {
continue;
}
try {
double lon = Double.parseDouble(traffic.getUserLon());
double lat = Double.parseDouble(traffic.getUserLat());
// 检查是否在可视区域内
if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) {
continue;
}
// 计算所属区域
int colIndex = Math.min((int) ((lon - minLon) / lonStep), gridCols - 1);
int rowIndex = Math.min((int) ((lat - minLat) / latStep), gridRows - 1);
String regionKey = rowIndex + "_" + colIndex;
// 构建OS key只按OS分组不包含版本号
String os = traffic.getOs() != null ? traffic.getOs() : "";
String osKey = os.toLowerCase().trim();
if (osKey.isEmpty()) {
continue; // 跳过没有OS信息的记录
}
// 计算总流量
double totalTraffic = (traffic.getUploadTraffic() != null ? traffic.getUploadTraffic() : 0.0) +
(traffic.getDownloadTraffic() != null ? traffic.getDownloadTraffic() : 0.0);
// 累计流量
regionOsTrafficMap.computeIfAbsent(regionKey, k -> new HashMap<>())
.merge(osKey, totalTraffic, Double::sum);
regionRecordCountMap.merge(regionKey, 1L, Long::sum);
// 保存OS key对应的OS名称保留原始大小写
osNameMap.put(osKey, os);
} catch (NumberFormatException e) {
// 忽略无效的经纬度数据
continue;
}
}
// 6. 找出每个区域的top1 手机OS
List<com.bigdata.dto.OsTrafficRegionTopDTO> result = new ArrayList<>();
for (int row = 0; row < gridRows; row++) {
for (int col = 0; col < gridCols; col++) {
String regionKey = row + "_" + col;
Map<String, Double> osTrafficMap = regionOsTrafficMap.get(regionKey);
if (osTrafficMap == null || osTrafficMap.isEmpty()) {
continue; // 该区域没有数据,跳过
}
// 找出流量最大的OS
Map.Entry<String, Double> topOs = osTrafficMap.entrySet().stream()
.max(Map.Entry.comparingByValue())
.orElse(null);
if (topOs != null) {
String osKey = topOs.getKey();
String osName = osNameMap.getOrDefault(osKey, osKey);
// 计算区域中心点
double centerLon = minLon + (col + 0.5) * lonStep;
double centerLat = minLat + (row + 0.5) * latStep;
com.bigdata.dto.OsTrafficRegionTopDTO dto = new com.bigdata.dto.OsTrafficRegionTopDTO();
dto.setRowIndex(row);
dto.setColIndex(col);
dto.setCenterLon(centerLon);
dto.setCenterLat(centerLat);
dto.setOsName(osName);
dto.setOs(osName);
dto.setTotalTraffic(topOs.getValue());
dto.setRecordCount(regionRecordCountMap.getOrDefault(regionKey, 0L));
result.add(dto);
}
}
}
return result;
}