生成机构树 除了递归还有别的方法吗

2019-11-26 09:51:04 +08:00
 tubimasky

1w6 数据

如果从总公司开始 最多有 7 级

mybatis 自查询 /java 递归查数据库 大概 30s

java 全查 代码递归生成机构树 大概 10s

3986 次点击
所在节点    问与答
30 条回复
siroleaf
2019-11-26 10:05:49 +08:00
用个 json 缓存起来。每当机构更新时去更新缓存的相应树节点就好。 查询机构树直接用缓存的
12tall
2019-11-26 10:07:41 +08:00
感觉可以通过先行数据结构(例如哈希表)构造树,可能会好一些吧
因为我没试过,所以也不知道具体效率如何

而且机构树这种弄一个静态的应该比较合适吧,开始时查询一次,后面就修改时更新。
这个我试了,感觉还行~
learnshare
2019-11-26 10:12:44 +08:00
缓存是一种方式
另一种方式是分层级获取,比如刚开始只获取前两级,再根据父级查对应的子级(不过要考虑实际的使用场景)
tubimasky
2019-11-26 10:14:47 +08:00
@siroleaf #1 不太行 也可能是查某个分公司的下级
helloSpringBoot
2019-11-26 10:20:53 +08:00
这个能满足吗,我们项目在用: https://jgrapht.org/
joysir
2019-11-26 10:21:54 +08:00
如果是多层,数据库表结构应该用一颗树表示(左值、右值的形式),而不是纯用 parentId 来做关联。
tubimasky
2019-11-26 10:29:14 +08:00
@learnshare #3 得提供所有下级 结果可以缓存 也就是总公司才这么慢 华东大区 3000 多条 java 大概是几百 ms
javapythongo
2019-11-26 10:44:12 +08:00
延迟加载?
tubimasky
2019-11-26 10:50:14 +08:00
@helloSpringBoot #5 好像不太一样哈
rrfeng
2019-11-26 10:53:19 +08:00
我给你个方案,直接用目录式存储,比如 ETCD (逃
wysnylc
2019-11-26 10:55:22 +08:00
丢 redis 缓存
想要响应快就得数据有延迟
想要数据没延迟就要接受响应慢
同样的油量,你不能让一辆车跑得又快又远
luckyrayyy
2019-11-26 11:00:55 +08:00
插入的时候构建啊,不要每次读取的时候构建。这种数据应该是变动不太大的吧
wc951
2019-11-26 11:04:33 +08:00
用 ldap 存
x66
2019-11-26 11:25:57 +08:00
关键词:树形结构的数据库表 Schema 设计
cokolin
2019-11-26 11:32:34 +08:00
1. 缓存是一定可以的,我不相信公司机构会经常变化
2. 如果要查数据,可以加一两个表字段表示上层结构,甚至可以直接用 id 也可以,思路如下:
例如一个字段:level_index = 1020030040050060007
其中 1 ~ 7 表示各个层级关系,然后你要找第四层级某个部门的所有数据可以查询:
level_index > 1020030040000000000 and level_index < 1020030050000000000
aguesuka
2019-11-26 12:38:49 +08:00
缓存肯定要做,数据结构大概是 Node<E> {E data; Set<Node<E>> children; Node parent} 的结构;用 Hash 来构造,时间复杂度是 O(n),只要知道某个机构的 Node 就能找到它的子所有机构。为此你可以在建立一个 HashMap<ID, Node<E>> index;
这样你前台传过来一个机构 id,返回所有子节点的代码大概就是:
ID id;
int deep ;
//...
Node<E> node = index.get(id);
return traversing(node,deep); // traversing 是遍历所有子节点的方法,deep 是深度
blodside
2019-11-26 13:10:45 +08:00
16k 条数据怎么会要十秒的, 我想不通啊
aguesuka
2019-11-26 13:12:35 +08:00
···
public class TreeBuilderTest {
private <E, ID> Node<E> buildTree(Collection<E> elements, Function<E, ID> getId, Function<E, ID> getParentId) {
Map<ID, Node<E>> idNodeMap = elements.stream().collect(Collectors.toMap(getId, Node::new));
Node<E> root = null;
for (E element : elements) {
ID parentId = getParentId.apply(element);
ID selfId = getId.apply(element);
Node<E> selfNode = idNodeMap.get(selfId);
if (idNodeMap.containsKey(parentId)) {
Node<E> parentNode = idNodeMap.get(parentId);

parentNode.children.add(selfNode);
selfNode.parent = parentNode;
} else {
if (root != null) {
throw new IllegalArgumentException("root node more than one");
}
root = selfNode;
}
}
Objects.requireNonNull(root, "there is not root node");
return root;
}

@Test
public void test() {
Random random = new SecureRandom();
List<TestData> resultFromSql = IntStream.range(0, 100_000)
.mapToObj(i -> new TestData(i, random))
.collect(Collectors.toList());
long startTime = System.nanoTime();
Node<TestData> testDataNode = buildTree(resultFromSql, e -> e.id, e -> e.parentId);
System.out.println("cost = " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
}

private static class Node<E> {
E data;
Set<Node<E>> children;
Node<E> parent;

Node(E data) {
this.data = data;
children = new HashSet<>();
}
}

private static class TestData {
int id;
int parentId;

TestData(int id, Random r) {
this.id = id;
parentId = id == 0 ? -1 : r.nextInt(id);
}
}
}
···
抛砖引玉,十万条数据在我这里只要 0.1 秒。我觉得构造树的时间可以忽略不记。
tubimasky
2019-11-26 14:39:07 +08:00
@luckyrayyy #12 数据是来自其它系统的库


@blodside #17 16k 我写的是递归 16k 次
@aguesuka #18 感谢 我试试 能不能 套进去
allenyang89
2019-11-26 14:43:04 +08:00
一个表存 id 节点树结构直接扔内存里也没多少,具体信息根据 id 再查

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/623139

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX