mongodb 中的递归查找子目录

2021-12-01 16:44:01 +08:00
 among

# 目录表
class TC_struct(Document):
    name = StringField()    #目录名
    parent = ObjectIdField()    #上层目录的 id


# 文件表
class TC_item(Document):
    # 所在目录
    parent = ReferenceField(TC_struct) #所在的目录

根据目录,递归查找目录中的所有文件。

#先找到所有的目录。path_id 为所选择目录的 id path_ls = recurs_path(TC_struct, path_id)

#然后找到目录下的所有文件 qry_list = Q(parent__in=path_ls)

#递归查找目录的方法。

def recurs_path(tb_cls, path_id):
    rds = tb_cls.objects(parent=ObjectId(path_id)).only('id')
    rt = list()
    rt.append(ObjectId(path_id))
    for rd in rds:
        # 递归查找子目录中的子目录
        rt.extend(recurs_path(tb_cls, rd._id))
    return rt

现在的问题是,如果目录结构很深,如有 4000 多个目录,在递归的时候,耗时特别长。

有没有方法,可以提升递归时的效率。 根本的需求是:递归查找目录中的所有文件。

2007 次点击
所在节点    MongoDB
11 条回复
among
2021-12-01 16:48:59 +08:00
4000 多个字目录,响应时间能有 4s 多。
ipwx
2021-12-01 16:59:21 +08:00
就算是操作系统上面递归子目录也这么慢啊。。。

你要检索的时候秒出结果,你就需要加索引:

1. 要么把所有目录的前缀抽出来当 tag 扔进倒排索引。
2. 要么找个支持前缀匹配的数据库。

说实话你可以自己写一个程序挂在那里跑,专门维护内存索引,绝对不慢
among
2021-12-01 17:27:54 +08:00
mongodb 中的 aggregate 能否支持这种。
libook
2021-12-01 17:45:12 +08:00
你可以先查叶子目录名,看有几个符合要求的,然后再想根递归查询,中间不符合要求的过滤掉,越靠近根目录,候选就越少,最终剩下一个到根目录的候选就是你要的结果,或者到根之前 0 候选就表明目录不存在。然后拿着叶子目录的 ID 去文件表里查,可以一次性查到。

不知道你的场景这样是不是会有效。
rushpu
2021-12-01 17:49:47 +08:00
among
2021-12-01 17:51:37 +08:00
@libook

现在的算法就是根据跟的 id ,查找他目录下面的字目录,然后在递归查找这个子目录中子目录,一层层递归。
最后得到所有的目录的 id 的 list , 最后根据这个 list ,找到目录在这些 list 中的文件。

请过时间分析,时间都花在递归目录上了,查找文件很快。
fgwmlhdkkkw
2021-12-01 17:53:06 +08:00
做所有文件名和所有_id 的索引……
fgwmlhdkkkw
2021-12-01 17:54:03 +08:00
或者说,存的时候就倒着存。
libook
2021-12-01 17:59:06 +08:00
@among #6 要不然就是空间换时间,你把所有目录的完整路径存到一个
libook
2021-12-01 17:59:43 +08:00
@among #6 要不然就是空间换时间,你把所有目录的完整路径存到一个单独的表里,用字符串一次性匹配。
zzl22100048
2021-12-01 18:24:37 +08:00
改成对象存储的那种模式,前缀匹配

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

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

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

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

© 2021 V2EX