V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐工具
RoboMongo
推荐书目
50 Tips and Tricks for MongoDB Developers
Related Blogs
Snail in a Turtleneck
among
V2EX  ›  MongoDB

mongodb 中的递归查找子目录

  •  1
     
  •   among · 57 天前 · 691 次点击
    这是一个创建于 57 天前的主题,其中的信息可能已经有所发展或是发生改变。

    # 目录表
    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 多个目录,在递归的时候,耗时特别长。

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

    11 条回复    2021-12-01 18:24:37 +08:00
    among
        1
    among  
    OP
       57 天前
    4000 多个字目录,响应时间能有 4s 多。
    ipwx
        2
    ipwx  
       57 天前
    就算是操作系统上面递归子目录也这么慢啊。。。

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

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

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

    不知道你的场景这样是不是会有效。
    rushpu
        5
    rushpu  
       57 天前   ❤️ 1
    among
        6
    among  
    OP
       57 天前
    @libook

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

    请过时间分析,时间都花在递归目录上了,查找文件很快。
    fgwmlhdkkkw
        7
    fgwmlhdkkkw  
       57 天前
    做所有文件名和所有_id 的索引……
    fgwmlhdkkkw
        8
    fgwmlhdkkkw  
       57 天前
    或者说,存的时候就倒着存。
    libook
        9
    libook  
       57 天前
    @among #6 要不然就是空间换时间,你把所有目录的完整路径存到一个
    libook
        10
    libook  
       57 天前
    @among #6 要不然就是空间换时间,你把所有目录的完整路径存到一个单独的表里,用字符串一次性匹配。
    zzl22100048
        11
    zzl22100048  
       57 天前
    改成对象存储的那种模式,前缀匹配
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2398 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 11:54 · PVG 19:54 · LAX 03:54 · JFK 06:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.