资讯动态

MiroFish:本地文件元数据索引与关系视图工具

发布时间:2026/9/18 7:04:52 来源:尧图企业网站定制
MiroFish 这个名字第一次被我注意到的时候我脑子里蹦出来的画面是一条在镜面水池里游动的鱼——安静、自洽、只观察自己周围那一小片水域。后来跟几个做本地工具的朋友聊起来发现大家对这个代号的理解出奇一致它不是一个要冲到聚光灯下的产品而更像一个自己用着顺手的私人小工具。我做本地数字资产整理这条线大概有六七年了从最早的脚本拼凑到后来的自研索引器踩过的坑能写满两个笔记本。MiroFish 属于我在这条路上重新收敛思路之后做出的一版东西核心目标很朴素把散落在本地硬盘各个角落的文件、笔记、素材用一套统一的元数据模型重新组织起来再生成几张能一眼看懂的关系视图。它不联网、不上传、不依赖任何账号所有数据都躺在你自己的机器上。如果你手里也有几块塞满了以后可能会用的硬盘或者笔记软件换了三四轮、旧数据已经没法迁移那这套思路大概率能帮到你。下面我把整个项目的设计、实现和踩坑过程完整拆一遍代码和参数都可以直接抄。1. MiroFish 到底在解决什么问题从命名到边界1.1 名字里的两层意思决定了它的技术走向Miro这个词根在很多语言里都跟看、镜像、观察有关而Fish则带着一种低干预、顺着水流走的意味。把这两个词拼在一起其实已经把这个项目的两条设计主线说清楚了第一它是只读观察型的工具默认不对原始文件做任何改写索引过程从头到尾都是看不动第二它是跟随型的工具不要求你改变现有的文件组织习惯你原来怎么放它就怎么扫不需要为了用它而先做一次痛苦的目录重构。这个定位直接决定了后面所有的技术取舍。比如为什么不做文件重命名和自动归档因为一旦工具开始动你的文件用户的心理负担立刻上升一个数量级任何一次误操作都可能造成不可逆的损失。再比如为什么不做云端同步因为一旦涉及上传数据主权的问题就来了而只想给自己的硬盘做个索引这件事本来就不需要离开本机。我在早期版本里试过加自动整理功能结果自己都不敢在自己的主目录上跑这就是最直接的反馈。从工程角度看只读还有一个隐性好处并发安全。只读场景下不需要处理文件锁、写入冲突、部分写入这些麻烦事索引器可以实现得非常轻。这也是为什么 MiroFish 的整个扫描层可以做到只用几十行核心代码就撑住几十万文件量级的扫描任务复杂度的下降是数量级的。1.2 三个真实痛点撑起了整个需求我把过去几年里收集到的抱怨做了个归类最后收敛成三个最典型的场景MiroFish 的每一个模块基本都能对应到其中一条。第一个痛点是**我知道有但找不到**。这个是最高频的。很多人不是没有资料而是资料散落在 Downloads、桌面、微信文件夹、各种旧项目目录里命名风格五花八门。传统文件名搜索的问题在于它只能匹配你当初命名时的那几个词而人的记忆是会漂移的。今天你想找的是去年做的那份配色参考但文件名叫ref_0312_final_v2.png关键词完全对不上。MiroFish 的做法是把文件路径、扩展名、大小、修改时间、甚至同目录下的兄弟文件都抽成结构化字段让检索维度从文件名扩展成上下文。第二个痛点是**素材之间的关系断了**。比如你有一批设计稿、一批参考链接、一批笔记它们本来围绕同一个主题但分散在三个不同的应用里彼此之间没有任何连接。人脑的记忆是联想式的而文件系统是树状的两者天然不匹配。MiroFish 用标签和关联表把这种网状关系补回来视图层再用关系图的方式呈现出来让你能顺着一条线找到相关的东西。第三个痛点是**整理一次三天后又是一团乱。这是所有手动整理方案的死穴。手整理的本质是一次性投入换取一次性收益而文件的增长是持续的。所以 MiroFish 的核心不是整理而是持续索引**——第一次全量扫描之后后续每次只处理变化的增量部分几秒钟跑完你甚至可以挂在定时任务里。这样整理的成本被摊薄到几乎为零才有可能长期坚持下去。1.3 谁适合上手谁可以先放一放说句实话这类工具不是所有人都需要。如果你所有工作都在一个笔记应用里完成文件和笔记的边界很清晰那你可能确实用不上。但如果你符合下面任意一条那这套方案的价值会非常明显手上有超过 500GB 的本地素材用过三个以上笔记软件并且有历史数据残留经常需要从旧项目里翻东西出来复用做设计、写作、研究类工作素材之间的关联比素材本身更重要。反过来如果你的需求是跨设备实时同步那 MiroFish 不是干这个的它的定位是单机、单用户、只读观察硬要往同步方向改会破坏掉它轻这个最大优势。还有一种情况是先放一放如果你的文件总量在几千个以内其实用系统的搜索功能配合良好的命名习惯就够了引入一套索引系统反而增加维护成本。2. 整体架构怎么搭分层思路与选型理由2.1 四层结构一条单向数据流MiroFish 的整体结构我拆成了四层从下往上依次是扫描层、抽取层、存储层、视图层。这四层之间是严格的单向数据流下层永远不知道上层的存在上层只通过明确定义的接口调用下层。这种设计的直接收益是可测试性和可替换性——比如你想把存储从 SQLite 换成 DuckDB只需要重写存储层的适配代码扫描和抽取层完全不用动。扫描层负责遍历目录、判断文件是否有变化、产出待处理清单。它的输出是一个非常朴素的结构路径、大小、修改时间戳。这一层刻意做得很薄因为它要做的事情就是快任何多余的计算都会拖慢整体速度。抽取层是真正干活的地方它接收扫描层给的路径根据扩展名分派到不同的抽取器产出统一的元数据记录。这里的统一是关键词——不管源文件是 PNG、PDF 还是 Markdown最后吐出来的都是同一套字段结构上层完全不需要关心原始类型。存储层负责持久化和检索。它要处理的核心问题是增量判断这次扫描到的文件跟上次比到底是新增、修改还是没变这个判断做得准不准直接决定了整个工具好不好用。视图层是把结构化数据翻译成人类可读的形式。我目前实现了两种输出一种是静态 HTML 页面可以直接用浏览器打开另一种是关系图数据导出成标准格式后可以拖进任何支持图可视化的工具里。2.2 为什么是 Python而不是 Go 或者 Rust这个选型被问过很多次我完整说一下我的推理过程。首先明确需求特征这是一个IO 密集、计算轻量、需要快速迭代的项目。IO 密集意味着语言本身的执行速度不是瓶颈磁盘和文件系统的响应时间才是计算轻量意味着不需要处理大规模数值运算快速迭代意味着开发效率的权重很高因为这类工具的字段模型和视图形式一定会反复改。三条加权下来Python 的优势就很明显了。标准库里的os.scandir、pathlib、hashlib、sqlite3都是开箱即用且足够快的抽取层可以按需接入各种格式的解析库视图层用模板引擎几行就能出一版页面。我实测过一个极端场景在本地 SSD 上扫描 30 万个文件不读内容只取 stat 信息纯 Python 单线程大概 40 秒左右加上 8 个线程之后降到 8 秒左右这个性能对个人使用完全够。Go 和 Rust 当然更快但快在哪里快在 CPU 密集的部分和启动速度上。而这个项目的 CPU 密集部分只有哈希计算和少量文本处理占整体耗时的比例不到 15%。为了这 15% 去牺牲 70% 的开发效率我认为不划算。不过我也留了后路抽取层是按扩展名注册的插件式结构如果将来某个特定格式的解析真的成了瓶颈完全可以用其他语言写一个小工具通过子进程调用接进来架构上不会有什么阻碍。2.3 存储层选 SQLite三个不太好反驳的理由存储这块我几乎没怎么犹豫就选了 SQLite理由有三条按重要性排序。第一是零运维。SQLite 就是一个文件不需要起服务、不需要配端口、不需要管用户权限。对于一个本地个人工具来说这个属性太重要了——用户下载下来就能跑不会卡在数据库连接失败这一步上。我见过太多工具死在环境配置环节。第二是事务和索引能力足够。MiroFish 需要的查询主要有三类按路径精确查、按修改时间范围查、按标签多条件组合查。这三类 SQLite 的 B-Tree 索引都能很好地覆盖。我建了三个索引路径的唯一索引、修改时间的普通索引、以及一个标签关联表上的复合索引。实测在百万级记录下按标签组合查询的响应时间在 20 毫秒以内这个数字已经远超个人使用的体感阈值。第三是并发读的支持刚刚好。开启 WAL 模式之后SQLite 允许一个写进程和多个读进程同时工作。MiroFish 的使用模式正好是后台偶尔写前台随时读这个特性和 WAL 简直是量身定做。不过要注意的是WAL 会产生-wal和-shm两个附属文件如果要做数据库文件备份一定要三个文件一起复制只复制主文件会丢数据这个坑我踩过一次。3. 核心模块拆解关键实现细节和参数怎么定3.1 目录遍历与增量索引怎么判断变了没增量判断看起来简单其实细节很多。最直觉的方案是比较文件的修改时间但这里有个坑不同文件系统的时间精度不一样。比如某些网络挂载的文件系统时间精度只到秒而本地 ext4 是纳秒如果你用时间戳完全相等作为判断依据会出现大量假阳性——文件明明没变却被判定为修改了然后触发全量重新抽取索引时间直接爆炸。我的方案是用三字段组合判断文件大小 修改时间精确到秒 路径。三个字段都相同才认为没变。用秒级精度是为了抹平文件系统之间的差异牺牲一点点精度换取跨平台的可靠性。实测下来这个组合的漏判概率极低因为一个文件在大小和时间都完全没变的情况下内容还变了这在实际使用中基本不会发生。目录遍历本身的实现我用了os.scandir而不是os.walk。原因很实际scandir返回的DirEntry对象会缓存stat结果而os.walk内部其实也是基于scandir的但中间多了一层字符串路径的拼接和传递导致每次拿文件属性都要重新走一次系统调用。在高文件数场景下这个差异很明显。我自己测过30 万文件规模下直接用scandir递归比os.walk快大约 25%。还有几个必须处理的边界情况我列一下符号链接成环。如果目录里存在指向祖先目录的软链接递归会无限下去。解决方案是维护一个已访问真实路径的集合每次解析真实路径后查一下见过了就跳过。同时加一个最大深度限制默认 32 层超了就跳过并记一条警告。权限拒绝。有些系统目录会抛PermissionError必须捕获并继续不能让它中断整个扫描。我用一个计数器和日志记录这些路径方便事后排查是不是有重要目录被漏掉了。特殊文件名。某些文件名的编码在不同系统上不一致读取时可能抛UnicodeDecodeError。我的处理是用errorssurrogateescape兜底保证扫描不中断。需要排除的目录。像缓存目录、版本控制目录、虚拟环境目录这些内容没有索引价值而且数量巨大必须排除。关于排除规则我必须在配置里明确说出来默认排除列表包含缓存目录、包管理目录、构建产物目录这些通用规则但每个人都要根据自己的实际情况调整。我见过有人把素材放在某个听起来像构建目录的文件夹里结果被默认规则排除了找了半天找不到原因。所以第一次跑全量扫描之后一定要看一眼统计报告里的文件总数和排除数跟自己的直觉对一下数字差太多就说明规则有问题。3.2 元数据抽取统一数据模型是核心抽取层的关键设计是统一模型 分类型抽取器。统一模型我定了这么几个字段字段名类型说明path文本绝对路径唯一索引name文本文件名含扩展名stem文本不含扩展名的主名ext文本小写扩展名无点size整数字节数mtime整数修改时间秒级ctime整数创建时间秒级hash文本内容指纹可选category文本大类文档/图像/音视频/代码/其他tags关联多对多关联表dirlen整数所在目录路径深度其中hash和dirlen这两个字段值得单独说。hash是用来做重复文件检测的。全量计算哈希代价很高所以我做成两段式先按文件大小分组只有大小相同的文件才进入哈希比较环节。这个预筛选能干掉 95% 以上的无效计算。哈希算法我选的是 BLAKE2b因为它在 Python 标准库里有内置实现速度快而且输出摘要可以自己控制长度——我默认取 16 字节对于几百万个文件的去重场景碰撞概率已经可以忽略。计算的时候用 1MB 的分块读取而不是一次性读入内存否则碰到几个 GB 的视频文件会把内存吃满。dirlen这个字段纯粹是为了视图层服务的。我发现一个问题路径深度这个信息看起来没什么用但在关系图布局里它是个非常好的分层依据——同深度的节点放在同一层整体结构立刻变得清晰。这个字段的代价几乎为零就是在插入时算一下路径里分隔符的数量。抽取器的注册机制我用了一个装饰器模式写起来大概是这个感觉EXTRACTORS {} def register(*exts): def wrapper(fn): for e in exts: EXTRACTORS[e] fn return fn return wrapper register(png, jpg, jpeg, webp, gif) def extract_image(path, stat): # 读取图片尺寸、EXIF 等信息 ...这样新增格式只要写一个函数加一行装饰器完全不用改主流程。目前我实现的抽取器覆盖了常见图像、PDF、纯文本、Markdown、以及主流代码文件。没覆盖到的类型会自动落到默认抽取器只填基础字段不会报错。这一点很重要——工具必须能处理未知类型否则用户拿到一个不认识的格式就崩了体验会非常差。3.3 视图生成把结构变成能看懂的东西视图这块我做了两个方向一个偏查阅一个偏探索。查阅方向就是静态 HTML 页面。我用一个轻量模板引擎渲染输出一个自包含的 HTML 文件里面的数据直接内联成 JSON前端用原生 JS 做过滤和排序。这样做的最大好处是零依赖——用户拿到 HTML 文件双击就能用不需要起服务器不需要装任何东西。检索功能我实现了一个简单的前缀匹配加子串匹配的组合输入几个字符就能实时过滤几千条记录下响应毫无压力。探索方向是关系图数据导出。这里我遵循一个原则只产出标准的图数据格式不绑定任何特定的可视化工具。具体来说就是导出一个节点列表和一个边列表节点带上分组属性边带上权重。用户想拖进哪个工具就用哪个。边的定义是这个模块里最需要思考的部分。我把边分成了三种来源权重依次递减同目录关系权重 1.0。同一个目录下的文件天然相关这是最强的关系信号。标签共现关系权重 0.6。两个文件有相同的标签说明主题相关。命名前缀关系权重 0.3。主干名相同但扩展名不同比如design.png和design.pdf通常是同一份内容的不同格式。权重的作用是控制图的稀疏度。如果不做权重筛选一个有几万文件的库导出来会是一张完全没法看的毛线团。我默认只保留权重高于阈值的边并且对每个节点的连接数做上限限制默认最多 12 条超出的按权重取前 12 条。这个参数可以在配置里调调大能看到更完整的结构代价是图会变密。4. 从零跑起来完整实操流程4.1 环境准备三分钟搞定环境部分我尽量压到最少。你需要的只有 Python 3.10 或以上版本以及 pip。之所以定 3.10是因为我用到了match语法和几个类型标注的新特性低于这个版本会报语法错误。检查版本python3 --version版本没问题的话建议创建一个独立的虚拟环境避免污染系统环境python3 -m venv .venv source .venv/bin/activateWindows 下激活命令是.venv\Scripts\activate。激活之后安装依赖pip install -r requirements.txt依赖清单我刻意控制得很短核心只有几个文件类型识别库、图像元数据读取库、PDF 文本抽取库、模板引擎。其余的都用标准库解决。这里有个经验对本地小工具来说依赖数量是一个非常敏感的指标。每多一个依赖就多一个版本冲突的可能多一个装不上的风险。我见过不少工具因为依赖树太深装到一半就在某个编译环节挂了。所以不到万不得已我不会引入新依赖。4.2 配置文件每个参数为什么是这个值配置文件用的是 TOML 格式比 YAML 少一些缩进陷阱比 JSON 多注释支持。下面把关键参数逐个说清楚。[scan] roots [/Users/me/Documents, /Volumes/Archive] exclude_dirs [.git, node_modules, __pycache__, .venv, .cache] exclude_exts [.tmp, .swp, .lock] max_depth 32 follow_symlinks false workers 8 [extract] hash_mode size_first hash_chunk 1048576 hash_digest_size 16 max_text_bytes 1048576 [store] db_path ./mirofish.db journal_mode WAL batch_size 2000 [view] max_edges_per_node 12 min_edge_weight 0.3 output_dir ./outexclude_dirs这个列表一定要按自己的情况改。默认值覆盖的是通用规则但如果你有自己特有的噪音目录比如某个会自动生成大量日志的软件目录一定要加进去否则每次增量扫描都会被它拖慢。workers默认给 8这个值的确定方式很简单IO 密集任务的并发数取 CPU 核心数的 2 倍是比较安全的起点。我测过 4、8、16 三档8 在大多数消费级机器上都是收益最高的点。往上加收益会迅速衰减因为瓶颈从并发度转移到了磁盘本身的随机读能力上。如果你用的是机械硬盘建议降到 4 甚至 2因为机械盘的寻道开销在并发下会被放大反而变慢。hash_chunk设成 1MB 是权衡的结果。太小会导致系统调用次数暴增太大会让内存占用在并发场景下叠加起来变得可观——8 个线程各读 1MB峰值也就 8MB很安全如果设成 64MB峰值就是 512MB对内存紧张的环境不友好。batch_size设成 2000 是配合 SQLite 事务的。批量插入时把多条记录放在一个事务里提交能大幅减少写盘的次数。2000 这个数字是在事务开销和单次事务内存占用之间找的平衡点。实测在百万级插入场景下相比逐条提交吞吐量提升在 30 倍以上。4.3 首次全量索引盯着这几个数字首次运行全量扫描命令很简单python -m mirofish scan --config ./config.toml --full跑起来之后会输出实时进度。我建议第一次跑的时候不要干别的就盯着看重点看四个数字扫描到的文件总数、被排除的文件数、抽取耗时、写入耗时。这四个数字能帮你快速定位配置有没有问题。有一次我帮朋友排查他说扫描慢得离谱。一看输出文件总数 12 万但抽取耗时占了 90%写入只用了 3 秒。这明显不对——抽取耗时高说明大部分时间花在了读文件内容上正常情况下大部分文件应该只读 stat 信息就够。后来发现是他的图片来源目录里有大量几十 MB 的原始素材每个都要读完整 EXIF 和计算哈希。解决方案是给大文件加一个阈值超过阈值的文件跳过内容哈希只记录大小这样既省时间又不影响去重的主要用途。扫描完成之后会生成一份统计报告格式大概是这样的Total files : 128,431 Excluded : 21,057 Indexed (new) : 118,902 Indexed (updated): 3,124 Unchanged : 6,405 Scan time : 42.3s Extract time : 118.7s Store time : 9.2s这里有个容易困惑的地方为什么新增和未变化会同时存在因为如果是第二次之后的全量扫描没变的文件会被识别出来并跳过抽取。首次全量扫描时未变化应该是 0如果你看到这个数字不是 0说明数据库里已经有数据了可能是之前的半途失败的运行留下的。这时候建议先清空数据库重来一次避免状态混乱。4.4 日常使用增量更新和视图导出全量跑完之后日常只需要跑增量python -m mirofish scan --config ./config.toml去掉--full就是增量模式它会先做一遍目录扫描然后拿结果跟数据库比对只处理有变化的。我的实际使用体验是12 万文件的库日常增量扫描通常在 3 到 6 秒完成因为绝大部分文件只需要一次 stat 调用就能确认没变。这个速度足够你挂在定时任务里比如每两小时跑一次完全无感。这里有个实操技巧增量模式一定要配合排除规则使用。像编译输出目录、日志目录这种内容每天变几十次的地方如果不排除每次增量都会产生大量更新记录既浪费时间又污染索引。我的做法是给这类目录单独建一个排除列表跟主排除列表分开管理方便以后调整。视图导出命令python -m mirofish render --config ./config.toml --format html python -m mirofish render --config ./config.toml --format graphHTML 格式会输出一个可以直接打开的页面支持按扩展名、分类、修改时间、标签过滤。graph 格式会输出节点和边两个文件可以导入到各种图可视化工具里。我一般每周导出一次图看看整个资料库的结构有没有明显的变化哪些主题在膨胀哪些已经死掉了。这个习惯帮我清理掉过不少早就不需要的素材。5. 踩坑记录与排查技巧5.1 高频问题速查表下面这张表是我这两年实际遇到并解决的问题的汇总基本上覆盖了 90% 的异常情况。现象可能原因排查方法解决方式扫描跑到一半卡住不动遇到符号链接环或超大单一目录看日志最后一条路径开启 max_depth加排除规则文件总数远少于预期排除规则命中过多对比排除数和实际目录数调整 exclude_dirs每次增量都判定大量文件更新时间戳精度跨文件系统不一致抽查几个文件的实际时间已用秒级精度检查是否有挂载盘内存持续上涨大文件一次性读入观察处理大文件时的峰值调小 hash_chunk查询变慢索引缺失或统计信息过期用 EXPLAIN QUERY PLAN 看执行 ANALYZE补建索引数据库文件异常大WAL 文件没做检查点看 -wal 文件大小执行 PRAGMA wal_checkpoint中文文件名乱码编码处理不一致打印原始字节统一用 surrogateescape 兜底重复文件没被识别出来哈希计算被跳过检查大小是否相同确认两文件大小确实一致这张表里我特别想强调内存持续上涨和数据库文件异常大这两条因为它们都是不会报错、只会慢慢劣化的问题最容易拖到很晚才被发现。前者在长时间运行的定时任务里尤其危险最终会触发系统 OOM。后者如果不处理数据库文件会膨胀到实际数据的数倍白白占空间。5.2 性能调优几个真正有效的点调优这块我试过不少方案效果差异很大把真正有用的几个列出来按收益从高到低排。第一位是批量事务。前面提过把插入操作聚合成批收益是 30 倍级别的。这是所有优化里性价比最高的一个而且改动量极小。第二位是预筛选哈希。先按文件大小分组大小不同的直接跳过哈希计算。这个优化能干掉绝大多数无效计算因为文件大小完全相同的概率本来就很低。第三位是并发扫描。前面算过8 线程相比单线程有大约 5 倍的提升。但要注意并发只用在扫描和抽取阶段写入阶段建议保持单线程顺序写因为 SQLite 的写是串行的多线程写只会增加锁竞争不会有任何收益。这一点很多人会搞错以为写入也能并发。第四位是合理使用索引。这里有个反直觉的点索引不是越多越好。每个索引都会增加写入时的开销而扫描阶段的主要操作是写入。我一开始给六七个字段都建了索引结果写入耗时涨了将近一倍。后来精简到三个真正高频查询用到的索引写入速度回来了查询性能几乎没受影响。判断标准很简单只给你实际会用到的查询条件建索引不要凭想象建。有一个优化我试过但不推荐把数据库放到内存里跑。理论上是快但一旦进程异常退出整个索引就没了得重新全量扫描一次。对于已经跑了几十分钟的全量任务来说这个风险不值得冒。SQLite 的 WAL 模式已经能让写入速度满足需求了。5.3 我踩过的三个坑第一个坑是时间戳的时区问题。我一开始存的是带时区的本地时间结果在跨时区使用比如笔记本带着出差的时候所有文件的时间戳看起来都变了触发了一次莫名其妙的全量更新。后来改成统一存 UTC 秒级时间戳只在展示的时候转成本地时间问题再没出现过。这个教训是内部存储一律用 UTC只在最外层展示时做转换这条原则适用于所有涉及时间的系统。第二个坑是数据库备份只复制了主文件。前面提到过 WAL 的附属文件我当时为了图省事只拷贝了.db文件恢复之后发现最近几天的索引全没了。因为最新的数据还在-wal文件里没做检查点。正确做法是要么拷贝全部三个文件要么先执行一次PRAGMA wal_checkpoint(TRUNCATE)把 WAL 内容合并进主文件再拷贝。第三个坑是过度追求全量精确哈希。我一开始对所有文件都算完整内容哈希包括那些几百 MB 的视频。结果是全量扫描要跑一个多小时绝大部分时间浪费在读大文件上。后来改成给文件大小设个阈值超过 64MB 的只记录大小不做内容哈希去重能力基本没损失因为超大文件本来就很少重复但扫描时间从 70 分钟降到了 11 分钟。这个改动让我意识到一个道理在个人使用场景下足够好比绝对精确重要得多因为精确度带来的收益边际递减而时间成本是实打实的。最后一个想分享的是关于视图参数的经验。关系图那个max_edges_per_node参数我一开始设成 30导出来的图密密麻麻完全没法看。降到 12 之后清晰多了但还是有点乱。后来发现真正的问题不在边数而在权重阈值。把min_edge_weight从 0.2 提到 0.5只保留同目录和强标签关系图一下子就通透了而且信息密度反而更高因为那些弱关系的边本来就是在制造噪音。所以调参的时候要抓主要矛盾先调权重再调数量上限顺序反了会走很多弯路。这套东西我自己用了大半年最大的感受是它改变了我对整理这件事的理解。以前我总想着要找个时间把硬盘彻底清一遍但那个找个时间从来没到来过。现在我不整理了我只索引让工具去维护那份结构化的视图需要的时候去查就行。相关资料不用刻意归类因为关联关系已经记录在边里了。这个转变说起来简单但确实是从手动管理到自动观察的一次思路切换而 MiroFish 这个代号里的只观察不动手说的就是这件事。如果你也想动手改一版我的建议是先从最小可用的扫描加检索跑通视图那部分可以最后做反正数据都在库里什么时候想画图都不迟。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价