项目心得:广度遍历搜索部门处理业务

简介: 部门树节点 平常在做后台管理系统的时候,多多少少都会涉及部门管理,部门有上下级,所以架构会呈现出树形,下图是一个简单的部门节点图:                         这个和平时的二叉树很像,如果部门比较多的话,那么这个树就会很复杂。

部门树节点

平常在做后台管理系统的时候,多多少少都会涉及部门管理,部门有上下级,所以架构会呈现出树形,下图是一个简单的部门节点图:

 

 

 

 

 

 

 

 

 

 

 

 

这个和平时的二叉树很像,如果部门比较多的话,那么这个树就会很复杂。做到web上就会这样显示:

怎么实现的我就不详细介绍了,本文主要结合实例介绍平时项目中广度遍历搜索部门树,从上级部门往下级部门开始一级一级的遍历搜索。

假设需求

有个后台管理系统用来管理每个部门,还有每个部门的主机,现在每一个部门有一个IP段(192.168.1.1-192.168.1.100),该部门的主机注册的时候能够自动匹配段,并划分到该部门下。

分析需求

考虑到IP段重复的情况,可以采用广度遍历,就是从最上级部门开始,然后二级部门,然后三级部门....,这样的话能够节省IP匹配次数。

也是说希望最后的遍历搜索顺序是:根部门,行政,测试,管理,行政1,测试1,测试2,管理1,管理12

如下图所示:

广度优先遍历各个节点,需要使用到队列(Queue)这种数据结构,Queue的特点是先进先出,

其实也可以使用双端队列,区别就是双端队列首位都可以插入和弹出节点。整个遍历过程如下:

1.根部门进队列,处理业务,出队列,

2.行政,测试,管理进队列,处理业务,出队列

3.行政1,测试1,测试2,管理1进队列,处理业务,出队列

4,管理12进队列,处理业务,出队列

代码实现:

(注意这里使用了部分伪代码)

1. 缓存部门与下级部门

设计部门表的时候注意留一个字段是用来记录该部门的上级部门。

新建一个类,使用Map缓存部门id和下级部门idlist的形式

public class DeptManager{
    // 缓存部门id对应的所有下属部门id
    Map<Integer, List<Integer>> deptMap = new HashMap<Integer, List<Integer>>();
    // 缓存部门id对应的部门IP段
    Map<Integer, String> deptIpRangeMap = new HashMap<Integer, String>();

    /**
     * 加载 从数据库中取出所有部门信息,存储成List<Map<String, Object>>形式 加载部门id和其对应的IPRange
     * 注意数据库设计部门表的时候要添加上级部门ID字段
     * @throws Exception
     */
    public void load() throws Exception {
     // 从数据中获取所有部门信息
        List<Map<String, Object>> searchIdList = Db.biz.searchAsMapList(TbOrg.TABLE,
                new Field[] { TbOrg.ID, TbOrg.ORG_PARENT_ID, TbOrg.IP_RANGE });
        // 遍历部门,存储成部门ID对应下级部门IDList的形式
        for (Map<String, Object> searchId : searchIdList) {
       // 获取上级部门节点ID
int parentId = (Integer) searchId.get(TbOrg.ORG_PARENT_ID.name);
      // 获取当前部门节点ID
int id = (Integer) searchId.get(TbOrg.ID.name); if (deptMap.containsKey(parentId)) { deptMap.get(parentId).add(id); } else { List<Integer> idList = new ArrayList<Integer>(); idList.add(id); deptMap.put(parentId, idList); } // 缓存部门对应的IP段 deptIpRangeMap.put(id, (String) searchId.get(TbOrg.IP_RANGE.name)); } }

 

这样处理部门信息,接下里的部门信息就会被存储成上级部门ID对应下级部门list的一个键值对。例:
{-1=[1], 2=[4], 1=[2, 3]}存储成这样的形式是为了方便接下来更好的广度遍历。

 2.广度遍历部门

将部门信息存储成从上级部门往下级部门一级,二级,三级的形式

private static DeptManager deptManager = DeptManager.getInstance();

    private static List<List<Integer>> getDeptBroadList(int deptId) {
        List<List<Integer>> resultList = new ArrayList<List<Integer>>();
        // 队列控制广度遍历
        ArrayDeque<List<Integer>> queue = new ArrayDeque<List<Integer>>();
        List<Integer> subDeptList = deptManager.getSubDeptIds(deptId);
        queue.add(subDeptList);
        while (queue.isEmpty() == false) {
            subDeptList = queue.pop();
            resultList.add(subDeptList);
            // 获取部门节点的子节点
            List<Integer> children = getChildren(subDeptList);
            if (children != null && !children.isEmpty()) {
                queue.add(children);
            }
        }
        return resultList;
    }

    /**
     * 获取同一级所有子节点
     * 
     * @param list
     * @return
     */
    private static List<Integer> getChildren(List<Integer> list) {
        List<Integer> result = new ArrayList<Integer>();
        for (Integer deptId : list) {
            if (deptManager.getSubDeptIds(deptId) != null) {
                result.addAll(deptManager.getSubDeptIds(deptId));
            }
        }
        return result;
    }/**
     * 广度遍历匹配IP
     * 业务处理
     * @param hostIp
     * @param deptId
     * @return
     */
    private static int getDeptIdFromIp(String hostIp, int deptId) {
        // flag作为判断部门IP匹配的标志
        boolean flag = false;
        List<List<Integer>> deptBroadList = getDeptBroadList(deptId);
        for (List<Integer> list : deptBroadList) {
            for (int tempDeptId : list) {
                flag = matchDeptIp(hostIp, DeptManager.getInstance().getDeptIpRange(tempDeptId));
                if (flag) {
                    return tempDeptId;
                }
            }
        }
        // 未匹配到则返回根部门ID
        return deptId;
  }

 总结:

广度搜索在平常的项目中多多少少会使用到,本文只是作者个人经验见解,不到之处请与斧正。

代码段使用了部分伪代码希望帮助读者理解,希望本文能够给予读者在工作学习中帮助和参考。

个人博客网站 http://www.janti.cn
相关文章
|
人工智能 自然语言处理 搜索推荐
阿里云开放搜索重磅发布!云时代搜索业务的价值重构
【云栖大会】阿里云开放搜索重磅发布~
6879 0
阿里云开放搜索重磅发布!云时代搜索业务的价值重构
|
6月前
|
搜索推荐 测试技术 流计算
承上启下:基于全域漏斗分析的主搜深度统一粗排
文章首先介绍了淘宝搜索的多阶段检索系统,包括召回、粗排和精排阶段。粗排模型的目标是优化商品的排序,以提高在召回集合中选择优质商品的能力。文章提到,粗排模型与精排模型的目标有所不同,粗排更注重腰部商品的排序,而精排更注重头部商品的排序。 此外,文章还探讨了模型的损失函数形式,发现原始的softmax损失函数在处理多正样本时存在问题,提出了改进的损失函数,使得模型在粗排阶段的表现更佳。最后,作者们总结了优化工作的进展,以及优化样本对齐,以实现更好的整体效果。
|
算法
回溯与搜索 三 最高效益 选书
回溯与搜索 三 最高效益 选书
根据阿里巴巴职位层级,你的编程水平在什么位置?(附等级详细要求)
根据阿里巴巴职位层级,你的编程水平在什么位置?(附等级详细要求)
|
存储 监控 安全
数据人必知!认识数据“四种”分类“五大”价值,帮企业找到核心数据
在大数据时代,企业首先要做的是收集大量数据,但收集数据并非仅是把收集过来的数据放到数据存储平台里面那么简单,更重要的是对数据进行分类、加工及管理。
数据人必知!认识数据“四种”分类“五大”价值,帮企业找到核心数据
|
6月前
|
算法 关系型数据库 分布式数据库
如何用 PolarDB 整合age算法插件, 实现图式搜索加速 - 刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索
背景PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力.本文将介绍PolarDB结合图式算法, 实现高效率的刑侦、社交、风控、族谱、推荐等业...
198 0
|
存储 SQL 并行计算
如何用 PolarDB 整合age算法插件, 实现图式搜索加速 - 刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索
PolarDB 的云原生存算分离架构, 具备低廉的数据存储、高效扩展弹性、高速多机并行计算能力、高速数据搜索和处理; PolarDB与计算算法结合, 将实现双剑合璧, 推动业务数据的价值产出, 将数据变成生产力. 本文将介绍PolarDB结合图式算法, 实现高效率的刑侦、社交、风控、族谱、推荐等业务图谱类关系数据搜索.
394 0
|
监控 小程序 数据挖掘
5步法,快速找到数据分析思路
在工作中,经常有小伙伴遇到:做数据分析没思路的问题。如果是日常工作还好,可以对着以前的报表抄一份。但是面试时遇到没思路的问题,可能就含恨而终了。今天就分享下,如何快速找到思路。 比如被面试官问道:“你要如何分析一款APP”。此时忽然脑子短路,不知道从何说起,该怎么办呢?别着急,分五步,一步步来。
172 0
5步法,快速找到数据分析思路
|
搜索推荐 Serverless 定位技术
电商/O2O行业搜索排序表达式最佳实践
搭建搜索功能不难,难的是如何提高搜索质量,帮助用户快速找到心中所想的内容或商品,那么搜索结果的相关性排序则是影响用户体验最关键的一环,今天小编和大家聊一聊[开放搜索]几个典型的排序表达式的应用,如何更好的优化电商/O2O行业的排序效果.
3016 0
电商/O2O行业搜索排序表达式最佳实践