> 文档中心 > [树形结构]:通过多个顶点查询完整路径的目录结构

[树形结构]:通过多个顶点查询完整路径的目录结构


需求背景:

最近在搞数据研发平台,有个搜索相关的需求:用户可以通过Job名做模糊搜索,返回相关结果集,并且要携带出完整的目录结构,研发平台目录结构分四种: 根节点是工作空间,子节点有多层嵌套文件夹,文件夹里面是DAG工作流,工作流里是Job任务;需求是要返回完整的目录结构给前端。

解决方案:

这个问题就很有意思了,首先第一点就是树形结构了,因为是模糊搜索,返回的Job可能会多个,如果遍历的话,可能会出现多个完整目录结构,这时会需要做路径合并,难度很大;我改造了树形结构,下面直接上代码:

SearchNode:

定义当前节点的Key,和父类节点的key,都要保证唯一性;

text字段表示当前Node节点的其他字段,统一放入到Map集合中

children表示当前Node节点的子节点,结构是SearchNode的数组集合;

这里在做toString时直接转成JSON格式,且把Map集合中的数据也解出来,这里有个问题:

因为Map的value是Object类型,我这里是直接用正则匹配出数字类型的,不用加双引号,且如果是Boolean类型则也不加双引号;

@Data@AllArgsConstructor@NoArgsConstructorpublic class SearchNode {    private String  key;    private String  parentKey;    private Map text;    private List children;    private String regex = "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])";    public SearchNode(String key, String parentKey, Map text) { this.key = key; this.parentKey = parentKey; this.text = text;    }    @Override    public String toString() { final StringBuilder sb = new StringBuilder("{"); sb.append("\"key\":\"")  .append(key).append('\"'); sb.append(",\"parentKey\":\"")  .append(parentKey).append('\"'); text.forEach((k,v) -> {     sb.append(",\"").append(k).append("\":");     Pattern compile = Pattern.compile(regex);     Matcher matcher = compile.matcher(v.toString());     if (matcher.matches()) {  sb.append(v);     } else {  if (v.equals(true) || v.equals(false)) {      sb.append(v);  } else {      sb.append("\"").append(v).append("\"");  }     } }); sb.append(",\"children\":")  .append(children); sb.append('}'); return sb.toString();    }}

SearchTree:

这里是用递归思想获取树形结构,但是我们的需求背景是要拼接成一个完成的目录结构,而不是多个结构,所以选用Set集合去重思路,把重复的SearchNode干掉

public class SearchTree {    private HashSet searchNodeList = new HashSet();    public SearchTree(HashSet searchNodeList) { this.searchNodeList = searchNodeList;    }    //建立树形结构    public HashSet builTree(){ HashSet treeSearchNodes =new  HashSet(); for(SearchNode searchNodeNode : getRootNode()) {     searchNodeNode =buildChilTree(searchNodeNode);     treeSearchNodes.add(searchNodeNode); } return treeSearchNodes;    }    //递归,建立子树形结构    private SearchNode buildChilTree(SearchNode pNode){ List chilSearchNodes =new  ArrayList(); for(SearchNode searchNodeNode : searchNodeList) {     if(searchNodeNode.getParentKey().equals(pNode.getKey())) {  chilSearchNodes.add(buildChilTree(searchNodeNode));     } } pNode.setChildren(chilSearchNodes); return pNode;    }    //获取根节点    private List getRootNode() { List rootSearchNodeLists =new  ArrayList(); for(SearchNode searchNodeNode : searchNodeList) {     if(searchNodeNode.getParentKey().equals("head")) {  rootSearchNodeLists.add(searchNodeNode);     } } return rootSearchNodeLists;    }}

测试结果:

@SpringBootTestpublic class SearchNodeTests {    @Test    public void contextLoads() { HashSet menuList= new HashSet(); HashMap map1 = new HashMap(); map1.put("local","湖北省"); HashMap map2 = new HashMap(); map2.put("local","山东省"); HashMap map3 = new HashMap(); map3.put("local","武汉市"); HashMap map4 = new HashMap(); map4.put("local","仙桃市"); HashMap map5 = new HashMap(); map5.put("local","青岛市"); HashMap map6 = new HashMap(); map6.put("local","武昌区"); HashMap map7 = new HashMap(); map7.put("local","洪山区"); HashMap map8 = new HashMap(); map8.put("local","洪山街道"); /*插入一些数据*/ menuList.add(new SearchNode("1","head",map1)); menuList.add(new SearchNode("7","head",map2)); menuList.add(new SearchNode("2","1",map3)); menuList.add(new SearchNode("3","1",map4)); menuList.add(new SearchNode("8","7",map5)); menuList.add(new SearchNode("4","2",map6)); menuList.add(new SearchNode("5","2",map7)); menuList.add(new SearchNode("6","4",map8)); /*让我们创建树*/ SearchTree menuTree =new SearchTree(menuList); menuList=menuTree.builTree(); /*转为json看看效果*/ String jsonOutput= JSON.toJSONString(menuList); System.out.println("树状数据:"+menuList.toString()); System.out.println("树里面所有的id"+ this.list);//获取树里面的所有节点    }    List children=null;    //参数1:树结构  参数二:节点id    public List recursion (Menu tree, int node){ if(tree.getId()==node){     //节点id=需要查询的id     children = tree.getChildren();  //获取children里面的数据返回 }else {     for(Menu bean:tree.getChildren()){     //反之递归children里面的数据  recursion(bean,node);     } } return children;    }    List list = new ArrayList();//初始化id集合    //获取树里面的所有节点,调用方法前记得清空list    public void getAllNode(Menu tree) { list.add((long) tree.getId());//添加节点 if (tree.getChildren() != null) {//判断是否有子节点     for (Menu bean : tree.getChildren()) {//循环递归子节点  getAllNode(bean);     } }    }}