Files
Environment-Monitoring-System/Report/系统设计_第四部分.md
ChuXun 02a830145e 1
2025-10-25 19:18:43 +08:00

21 KiB
Raw Blame History

2.4 算法设计

本节详细描述了系统中的核心算法设计,这些算法是系统智能化和高效运行的关键。

2.4.1 A* 寻路算法

A*寻路算法是系统中的核心算法之一,用于为网格员规划从当前位置到任务目标点的最优路径。该算法在网格与地图模块中发挥着重要作用。

算法目的: 为网格员提供从当前位置到任务地点的最优(最短或最快)路径,避开障碍物。

算法输入:

  • startNode: 起始点坐标 (x, y)。
  • endNode: 目标点坐标 (x, y)。
  • grid: 包含障碍物信息的地图网格数据。

核心逻辑:

  1. 维护一个开放列表(openList)和一个关闭列表(closedList)。
    • openList: 存储待探索的节点使用优先队列实现按F值排序。
    • closedList: 存储已探索过的节点。
  2. openList 中选取F值G值+H值最小的节点作为当前节点。
    • G值: 从起点到当前节点的实际代价。
    • H值: 从当前节点到终点的预估代价(启发函数)。
    • F值: G值 + H值表示经过当前节点到达终点的总代价估计。
  3. 遍历当前节点的相邻节点(上、下、左、右四个方向)。
  4. 对于每个相邻节点:
    • 如果是障碍物或已在closedList中,则跳过。
    • 如果不在openList计算其G值、H值和F值将其加入openList,并记录其父节点为当前节点。
    • 如果已在openList检查经由当前节点到达该相邻节点的路径是否更优G值更小。如果更优则更新其G值、F值和父节点。
  5. 将当前节点从openList移除,加入closedList
  6. 重复步骤2-5直到
    • 找到目标节点(当前节点为终点)。
    • openList为空(无法找到路径)。
  7. 如果找到目标节点,通过回溯父节点构建从起点到终点的路径。

启发函数选择: 系统采用曼哈顿距离Manhattan Distance作为启发函数计算公式为

h(n) = |n.x - goal.x| + |n.y - goal.y|

这种启发函数适合网格化的移动模式,只允许上、下、左、右四个方向的移动。

算法实现:

public List<Point> findPath(Point start, Point end) {
    // 加载地图数据和障碍物信息
    List<MapGrid> mapGrids = mapGridRepository.findAll();
    Set<Point> obstacles = new HashSet<>();
    for (MapGrid gridCell : mapGrids) {
        if (gridCell.isObstacle()) {
            obstacles.add(new Point(gridCell.getX(), gridCell.getY()));
        }
    }
    
    // 初始化开放列表和所有节点映射
    PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
    Map<Point, Node> allNodes = new HashMap<>();
    
    // 创建起始节点
    Node startNode = new Node(start, null, 0, calculateHeuristic(start, end));
    openSet.add(startNode);
    allNodes.put(start, startNode);
    
    // 开始A*算法主循环
    while (!openSet.isEmpty()) {
        Node currentNode = openSet.poll();
        
        // 找到目标
        if (currentNode.point.equals(end)) {
            return reconstructPath(currentNode);
        }
        
        // 探索相邻节点
        for (Point neighborPoint : getNeighbors(currentNode.point)) {
            if (obstacles.contains(neighborPoint)) {
                continue; // 跳过障碍物
            }
            
            int tentativeG = currentNode.g + 1; // 相邻节点间距离为1
            Node neighborNode = allNodes.get(neighborPoint);
            
            if (neighborNode == null) {
                // 新节点
                int h = calculateHeuristic(neighborPoint, end);
                neighborNode = new Node(neighborPoint, currentNode, tentativeG, h);
                allNodes.put(neighborPoint, neighborNode);
                openSet.add(neighborNode);
            } else if (tentativeG < neighborNode.g) {
                // 找到更好的路径
                neighborNode.parent = currentNode;
                neighborNode.g = tentativeG;
                neighborNode.f = tentativeG + neighborNode.h;
                // 更新优先队列
                openSet.remove(neighborNode);
                openSet.add(neighborNode);
            }
        }
    }
    
    return Collections.emptyList(); // 没有找到路径
}

// 计算启发式函数值(曼哈顿距离)
private int calculateHeuristic(Point a, Point b) {
    return Math.abs(a.x() - b.x()) + Math.abs(a.y() - b.y());
}

// 获取相邻节点(上、下、左、右)
private List<Point> getNeighbors(Point point) {
    List<Point> neighbors = new ArrayList<>(4);
    int[] dx = {0, 0, 1, -1}; // 右、左、下、上
    int[] dy = {1, -1, 0, 0}; 
    
    for (int i = 0; i < 4; i++) {
        int newX = point.x() + dx[i];
        int newY = point.y() + dy[i];
        
        // 检查边界
        if (newX >= 0 && newX < mapWidth && newY >= 0 && newY < mapHeight) {
            neighbors.add(new Point(newX, newY));
        }
    }
    return neighbors;
}

// 重建路径
private List<Point> reconstructPath(Node node) {
    LinkedList<Point> path = new LinkedList<>();
    while (node != null) {
        path.addFirst(node.point);
        node = node.parent;
    }
    return path;
}

算法输出: 从起点到终点的一系列坐标点列表,表示规划好的路径。如果无法找到路径,则返回空列表。

算法应用: 在PathfindingController中通过/api/pathfinding/find接口暴露,网格员可以通过该接口获取从当前位置到任务地点的最优路径。

2.4.2 任务智能分配算法

任务智能分配算法是系统的另一个核心算法,用于在多个可用网格员中,为新任务选择最合适的执行者。

算法目的: 在多个可用网格员中,为新任务选择最合适的执行者,优化任务分配效率和完成质量。

算法输入:

  • task: 需要分配的任务对象。
  • availableWorkers: 可用的网格员列表。

核心逻辑: 这是一个复合策略算法,综合考虑多个因素,通过加权评分机制选择最合适的网格员:

  1. 地理距离评分:

    • 计算每个网格员当前位置到任务位置的距离。
    • 距离越近,评分越高。
    • 使用公式: distanceScore = maxDistance - distance,其中maxDistance是一个预设的最大考虑距离。
  2. 当前负载评分:

    • 评估每个网格员当前正在处理的任务数量。
    • 任务数量越少,评分越高。
    • 使用公式: loadScore = maxTasks - currentTasks,其中maxTasks是一个预设的最大任务数。
  3. 专业匹配度评分:

    • 根据任务类型和网格员的专业技能进行匹配。
    • 匹配度越高,评分越高。
    • 使用公式: skillScore = matchedSkills / requiredSkills.size()
  4. 历史表现评分:

    • 考虑网格员的历史完成率和质量评分。
    • 表现越好,评分越高。
    • 使用公式: performanceScore = (completionRate * 0.7) + (qualityRating * 0.3)
  5. 综合评分计算:

    • 对上述各项评分进行加权求和。
    • 使用公式: totalScore = (distanceScore * w1) + (loadScore * w2) + (skillScore * w3) + (performanceScore * w4)
    • 其中w1、w2、w3、w4是各项评分的权重且满足w1 + w2 + w3 + w4 = 1
  6. 选择最高评分的网格员:

    • 根据综合评分对网格员进行排序。
    • 选择评分最高的网格员作为推荐人选。

算法实现:

public UserAccount recommendWorkerForTask(Task task, List<UserAccount> availableWorkers) {
    if (availableWorkers.isEmpty()) {
        return null;
    }
    
    // 权重配置
    final double DISTANCE_WEIGHT = 0.4;
    final double LOAD_WEIGHT = 0.3;
    final double SKILL_WEIGHT = 0.2;
    final double PERFORMANCE_WEIGHT = 0.1;
    
    // 任务位置
    Point taskLocation = new Point(task.getGridX(), task.getGridY());
    
    // 计算每个网格员的评分
    Map<UserAccount, Double> workerScores = new HashMap<>();
    
    for (UserAccount worker : availableWorkers) {
        // 1. 地理距离评分
        Point workerLocation = new Point(worker.getGridX(), worker.getGridY());
        double distance = calculateDistance(workerLocation, taskLocation);
        double maxDistance = 10.0; // 最大考虑距离
        double distanceScore = Math.max(0, maxDistance - distance) / maxDistance;
        
        // 2. 当前负载评分
        int currentTasks = taskRepository.countByAssigneeIdAndStatusIn(
            worker.getId(), Arrays.asList(TaskStatus.ASSIGNED, TaskStatus.IN_PROGRESS));
        int maxTasks = 5; // 最大任务数
        double loadScore = (double)(maxTasks - currentTasks) / maxTasks;
        
        // 3. 专业匹配度评分
        double skillScore = calculateSkillMatch(worker, task);
        
        // 4. 历史表现评分
        double completionRate = workerStatsService.getCompletionRate(worker.getId());
        double qualityRating = workerStatsService.getAverageQualityRating(worker.getId());
        double performanceScore = (completionRate * 0.7) + (qualityRating * 0.3);
        
        // 5. 综合评分
        double totalScore = (distanceScore * DISTANCE_WEIGHT) +
                           (loadScore * LOAD_WEIGHT) +
                           (skillScore * SKILL_WEIGHT) +
                           (performanceScore * PERFORMANCE_WEIGHT);
                           
        workerScores.put(worker, totalScore);
    }
    
    // 选择评分最高的网格员
    return workerScores.entrySet().stream()
        .max(Map.Entry.comparingByValue())
        .map(Map.Entry::getKey)
        .orElse(null);
}

算法输出: 推荐的最佳网格员对象。如果没有合适的网格员则返回null。

算法应用: 在TaskAssignmentService中实现,当主管触发自动分配或系统基于反馈自动创建任务时调用。

2.5 数据持久化设计

系统采用了一种独特的数据持久化方案不使用传统的关系型数据库而是以JSON文件的形式存储所有数据。这种设计简化了部署和配置特别适合快速迭代和中小型应用场景。

2.5.1 JSON文件存储架构

系统的数据持久化层基于以下架构:

  1. 核心存储服务:

    • JsonStorageService: 提供对JSON文件的读写操作包括序列化和反序列化。
    • FileSystemService: 处理文件系统操作,如创建、读取、更新和删除文件。
  2. Repository层:

    • 为每种核心模型提供专门的Repository类UserRepositoryFeedbackRepository等。
    • 这些Repository类模拟了类似JPA的接口提供CRUD操作和查询功能。
    • 内部使用JsonStorageService进行实际的文件操作。
  3. 并发控制:

    • 使用文件锁机制确保在并发环境下的数据一致性。
    • 实现了简单的乐观锁定策略,通过版本号检测冲突。
  4. 索引和查询优化:

    • 在内存中维护索引结构,加速常见查询操作。
    • 支持基于字段值的过滤和排序。

2.5.2 核心JSON文件结构

系统中的每个核心模型对应一个JSON文件下面详细描述了这些文件的结构。

users.json - 用户账户数据

存储系统中所有用户的账户信息,包括认证信息和角色权限。

字段名 JSON数据类型 约束/说明 描述
id Number 唯一标识, 自增 用户的唯一标识符
name String 非空 用户姓名
phone String 非空, 唯一 手机号码,可用于登录
email String 非空, 唯一 电子邮箱,可用于登录
password String 非空, 长度>=8 加密后的用户密码
gender String (ENUM) 性别 (MALE, FEMALE, OTHER)
role String (ENUM) 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等)
status String 非空, (ENUM) 账户状态 (ACTIVE, INACTIVE, SUSPENDED)
grid_x Number 关联的网格X坐标 (主要用于网格员)
grid_y Number 关联的网格Y坐标 (主要用于网格员)
region String 所属区域或地区
level String (ENUM) 用户等级 (JUNIOR, SENIOR, EXPERT)
skills Array 技能列表 (JSON数组格式的字符串)
enabled Boolean 非空, 默认 true 账户是否启用
current_latitude Number 当前纬度坐标 (用于实时定位)
current_longitude Number 当前经度坐标 (用于实时定位)
failed_login_attempts Number 默认 0 连续失败登录次数
lockout_end_time String 账户锁定截止时间
created_at String 非空 记录创建时间
updated_at String 非空 记录最后更新时间
feedback.json - 环境问题反馈数据

存储用户提交的所有环境问题反馈信息。

字段名 JSON数据类型 约束/说明 描述
id Number 唯一标识, 自增 反馈的唯一标识符
event_id String 非空, 唯一 人类可读的事件ID
title String 非空 反馈标题
description String 问题详细描述
pollution_type String 非空, (ENUM) 污染类型 (AIR, WATER, SOIL, NOISE)
severity_level String 非空, (ENUM) 严重程度 (LOW, MEDIUM, HIGH, CRITICAL)
status String 非空, (ENUM) 反馈状态 (PENDING_REVIEW, PROCESSED等)
text_address String 文字描述的地址
grid_x Number 事发地网格X坐标
grid_y Number 事发地网格Y坐标
latitude Number 事发地纬度
longitude Number 事发地经度
submitter_id Number 外键 (FK) -> users.id (可为空) 提交者ID (公众提交时可为空)
attachments Array 附件列表 (包含文件路径等信息)
created_at String 非空 记录创建时间
updated_at String 非空 记录最后更新时间
tasks.json - 任务数据

存储系统中所有工作任务的信息。

字段名 JSON数据类型 约束/说明 描述
id Number 唯一标识, 自增 任务的唯一标识符
feedback_id Number 外键 (FK) -> feedback.id (可为空) 关联的原始反馈ID
assignee_id Number 外键 (FK) -> users.id (可为空) 任务执行人网格员ID
created_by Number 外键 (FK) -> users.id 任务创建人主管ID
status String 非空, (ENUM) 任务状态 (CREATED, ASSIGNED, IN_PROGRESS等)
title String 任务标题
description String 任务详细描述
pollution_type String (ENUM) 污染类型
severity_level String (ENUM) 严重程度
text_address String 任务地点文字描述
grid_x Number 任务地点网格X坐标
grid_y Number 任务地点网格Y坐标
latitude Number 任务地点纬度
longitude Number 任务地点经度
assigned_at String 任务分配时间
completed_at String 任务完成时间
created_at String 非空 记录创建时间
updated_at String 非空 记录最后更新时间
deadline String 任务截止日期
history Array 任务状态历史记录
submissions Array 任务提交记录
grids.json - 业务网格数据

存储系统中定义的地理网格信息。

字段名 JSON数据类型 约束/说明 描述
id Number 唯一标识, 自增 网格的唯一标识符
grid_x Number 网格X坐标
grid_y Number 网格Y坐标
city_name String 所属城市
district_name String 所属区县
description String 网格描述信息
is_obstacle Boolean 默认 false 是否为障碍物(如禁区)
created_at String 非空 记录创建时间
updated_at String 非空 记录最后更新时间
assignments.json - 任务分配记录数据

存储任务分配的详细记录。

字段名 JSON数据类型 约束/说明 描述
id Number 唯一标识, 自增 分配记录的唯一标识符
task_id Number 非空, 外键 (FK) -> tasks.id 关联的任务ID
assigner_id Number 非空, 外键 (FK) -> users.id 分配者主管ID
status String 非空, (ENUM) 分配状态
remarks String 分配备注
assignment_time String 非空 分配时间
deadline String 任务截止日期
created_at String 非空 记录创建时间
updated_at String 非空 记录最后更新时间