笔记重组
适用场景
当你的笔记库积累到一定程度,或者知识体系发生变化时,需要对笔记进行结构性调整。本文介绍笔记重组的核心技巧。
为什么需要重组笔记?
常见问题
随着笔记数量增长,你可能会遇到以下情况:
| 问题 | 表现 | 影响 |
|---|---|---|
| 内容分散 | 同一主题分散在多篇笔记中 | 信息碎片化,难以形成完整认知 |
| 笔记臃肿 | 单篇笔记内容过多过杂 | 重点不突出,难以阅读和维护 |
| 结构过时 | 笔记结构不再适应当前需求 | 查找困难,效率下降 |
| 重复内容 | 多篇笔记包含相似内容 | 维护成本高,容易产生冲突 |
重组的价值
yaml
重组收益:
知识整合: 将碎片信息整合为完整知识
结构优化: 建立更合理的知识架构
提升效率: 更快找到需要的内容
降低维护: 减少重复和冗余笔记合并
何时合并
遇到以下情况时,考虑合并笔记:
- 多篇笔记讨论同一主题
- 系列笔记更适合作为一篇完整文章
- 碎片化笔记难以单独理解
手动合并
基本步骤
yaml
合并流程:
1. 确定要合并的笔记列表
2. 创建或选择目标笔记
3. 复制内容到目标笔记
4. 整理结构和去重
5. 更新链接指向
6. 删除源笔记合并示例
假设你有以下碎片笔记:
markdown
# Python变量.md
## 变量定义
变量是存储数据的容器...
# Python数据类型.md
## 基本类型
Python 支持多种数据类型...
# Python运算符.md
## 算术运算符
用于数学计算...合并后:
markdown
# Python基础.md
## 变量
变量是存储数据的容器...
## 数据类型
Python 支持多种数据类型...
## 运算符
### 算术运算符
用于数学计算...使用插件合并
Note Composer 插件
专门用于笔记重组的插件:
yaml
功能:
- 合并笔记到目标笔记
- 自动更新所有链接
- 支持插入位置选择
- 保留创建时间等元数据使用方法:
- 安装 Note Composer 插件
- 选择要合并的笔记
- 右键 → 「Merge note into...」
- 选择目标笔记
- 选择内容插入位置
Templater 批量合并
javascript
<%*
// 合并指定文件夹下的所有笔记
const folder = "待合并";
const targetNote = "合并结果";
const files = app.vault.getMarkdownFiles()
.filter(f => f.path.startsWith(folder + "/") && f.name !== targetNote);
let content = `---\ntitle: ${targetNote}\ncreated: ${tp.date.now("YYYY-MM-DD")}\n---\n\n# ${targetNote}\n\n`;
for (const file of files) {
const fileContent = await app.vault.read(file);
content += `## ${file.basename}\n\n${fileContent}\n\n---\n\n`;
}
// 创建合并后的笔记
await app.vault.create(`${folder}/${targetNote}.md`, content);
console.log(`已合并 ${files.length} 篇笔记`);
%>合并后的整理
内容去重
检查并合并重复段落:
yaml
去重要点:
- 相同概念只保留一份
- 不同表述取更清晰的版本
- 冲突信息需要核实和统一结构重组
markdown
# 重组前(简单堆砌)
## 笔记A内容
...
## 笔记B内容
...
# 重组后(逻辑整合)
## 概述
## 基础概念
## 进阶内容
## 实践案例
## 参考资料链接更新
合并后需要更新其他笔记中的链接:
javascript
<%*
// 更新指向旧笔记的链接
const oldNames = ["Python变量", "Python数据类型", "Python运算符"];
const newName = "Python基础";
const allFiles = app.vault.getMarkdownFiles();
for (const file of allFiles) {
let content = await app.vault.read(file);
let modified = false;
for (const oldName of oldNames) {
const oldLink = `[[${oldName}]]`;
const newLink = `[[${newName}]]`;
if (content.includes(oldLink)) {
content = content.replaceAll(oldLink, newLink);
modified = true;
}
}
if (modified) {
await app.vault.modify(file, content);
console.log(`更新了 ${file.path} 中的链接`);
}
}
%>笔记拆分
何时拆分
以下情况建议拆分笔记:
- 笔记过长,阅读和维护困难
- 包含多个独立主题
- 部分内容需要单独引用
- 内容结构复杂,需要分层管理
拆分策略
按主题拆分
markdown
# 原笔记:项目管理完整指南.md(5000字)
## 拆分为:
- 项目管理概述.md
- 项目规划方法.md
- 项目执行技巧.md
- 项目风险管理.md
- 项目复盘总结.md按层级拆分
markdown
# 原笔记:编程学习.md
## 拆分为:
编程学习/
├── 编程学习索引.md # MOC 索引
├── Python/
│ ├── Python入门.md
│ └── Python进阶.md
├── JavaScript/
│ └── JavaScript基础.md
└── 算法/
└── 算法入门.md按时间拆分
markdown
# 原笔记:项目A会议记录.md(全年)
## 拆分为:
项目A/
├── 会议记录/
│ ├── 2024-01.md
│ ├── 2024-02.md
│ └── ...
└── 会议记录索引.md拆分操作
手动拆分
yaml
步骤:
1. 创建新的目标笔记
2. 剪切相关内容到新笔记
3. 在原笔记中添加链接
4. 添加必要的上下文信息
5. 检查链接是否需要更新使用插件拆分
Note Composer 拆分功能:
- 选中要拆分的内容
- 右键 → 「Extract to new note」
- 输入新笔记名称
- 选择是否在原笔记保留链接
Extract URL 插件:
将特定内容提取到新笔记:
yaml
操作:
1. 选中文本
2. 执行命令
3. 自动创建新笔记并插入链接拆分后的关联
创建索引笔记
markdown
# 编程学习索引
## Python
- [[Python入门]] - 基础语法和环境配置
- [[Python进阶]] - 面向对象和高级特性
## JavaScript
- [[JavaScript基础]] - 入门概念和语法
## 算法
- [[算法入门]] - 常见算法和数据结构添加导航链接
markdown
# Python入门.md
---
up: "[[编程学习索引]]"
next: "[[Python进阶]]"
---
## 内容
...
---
← [[编程学习索引]] | [[Python进阶]] →内容提取
提取场景
| 场景 | 说明 |
|---|---|
| 引用片段 | 将常用内容提取为独立笔记便于引用 |
| 核心概念 | 提取重要概念形成知识卡片 |
| 可复用内容 | 提取模板或示例代码 |
| 独立话题 | 将大话题中的子话题独立出来 |
提取方法
选中提取
yaml
快捷操作:
1. 选中要提取的内容
2. Ctrl+Shift+X 或使用命令
3. 输入新笔记名称
4. 自动在原位置插入链接使用 Templater 提取
javascript
<%*
// 提取选中内容到新笔记
const selection = app.workspace.getActiveViewOfType(MarkdownView).editor.getSelection();
if (selection) {
const noteName = await tp.system.prompt("输入新笔记名称");
if (noteName) {
const content = `# ${noteName}\n\n${selection}`;
await app.vault.create(`${noteName}.md`, content);
// 在原位置替换为链接
const editor = app.workspace.getActiveViewOfType(MarkdownView).editor;
editor.replaceSelection(`[[${noteName}]]`);
}
}
%>提取最佳实践
保留上下文
markdown
# 提取后的笔记应该包含
---
source: "[[原笔记名称]]"
extracted: 2024-03-15
---
## 内容
(提取的内容)
## 来源
摘自 [[原笔记名称#相关章节]]添加引用
markdown
# 原笔记
...正文内容...
> 相关内容详见 [[提取的笔记]]
...继续正文...结构重构
重构场景
- 知识体系升级
- 工作流程变化
- PARA/GTD 等方法调整
- 笔记库规模扩张
重构方法
文件夹重组
yaml
重组示例:
原: 笔记按时间组织
├── 2023/
├── 2024/
└── 临时/
新: 按 PARA 方法组织
├── 0-收件箱/
├── 1-项目/
├── 2-领域/
├── 3-资源/
└── 4-归档/批量移动脚本:
javascript
<%*
// 按 PARA 方法重组笔记
const movements = [
{ from: "项目/", to: "1-项目/" },
{ from: "学习/", to: "3-资源/" },
{ from: "归档/", to: "4-归档/" }
];
for (const { from, to } of movements) {
const files = app.vault.getMarkdownFiles()
.filter(f => f.path.startsWith(from));
for (const file of files) {
const newPath = file.path.replace(from, to);
await app.fileManager.renameFile(file, newPath);
console.log(`移动: ${file.path} -> ${newPath}`);
}
}
%>标签体系重构
yaml
# 旧标签体系
#工作 #学习 #生活
# 新标签体系(层级化)
#领域/工作
#领域/学习
#领域/生活
#状态/进行中
#状态/已完成批量修改标签:
javascript
<%*
// 重命名标签
const tagMap = {
"#工作": "#领域/工作",
"#学习": "#领域/学习",
"#生活": "#领域/生活"
};
const files = app.vault.getMarkdownFiles();
for (const file of files) {
let content = await app.vault.read(file);
let modified = false;
for (const [oldTag, newTag] of Object.entries(tagMap)) {
if (content.includes(oldTag)) {
content = content.replaceAll(oldTag, newTag);
modified = true;
}
}
if (modified) {
await app.vault.modify(file, content);
}
}
%>MOC 重建
重建知识地图索引:
markdown
# 主索引 MOC
## 领域知识
### 编程
- [[编程/MOC]]
### 设计
- [[设计/MOC]]
## 项目
- [[项目索引]]
## 资源
- [[读书笔记索引]]
- [[资源收藏索引]]归档整理
归档原则
yaml
归档判断标准:
项目完成: 已结束的项目笔记
时效过期: 不再适用的信息
参考价值低: 很少查阅的笔记
冗余内容: 已整合或过时的笔记归档流程
1. 识别归档候选
使用 Dataview 查询:
dataview
TABLE file.mtime as "最后修改", file.inlinks as "引用数"
FROM ""
WHERE file.mtime < date(today) - dur(180 days)
AND length(file.inlinks) < 2
SORT file.mtime ASC
LIMIT 502. 归档前处理
yaml
处理步骤:
- 检查是否有重要链接需要保留
- 确认内容是否已整合到其他笔记
- 添加归档标记或移动到归档文件夹3. 执行归档
方法一:移动到归档文件夹
javascript
<%*
// 归档旧笔记
const archivePath = "归档";
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - 180);
const files = app.vault.getMarkdownFiles()
.filter(f => {
return f.stat.mtime < cutoffDate.getTime()
&& !f.path.startsWith(archivePath);
});
for (const file of files) {
const newPath = `${archivePath}/${file.name}`;
await app.fileManager.renameFile(file, newPath);
console.log(`已归档: ${file.name}`);
}
%>方法二:添加归档属性
yaml
---
status: archived
archived_date: 2024-03-15
---4. 清理冗余
yaml
可删除内容:
- 空笔记
- 未使用的附件
- 过时的临时笔记
- 重复的内容重组工具
推荐插件
| 插件 | 功能 | 适用场景 |
|---|---|---|
| Note Composer | 合并、拆分、提取 | 综合重组 |
| File Cleaner | 清理空文件和附件 | 归档整理 |
| Templater | 自定义重组脚本 | 批量处理 |
| Dataview | 查询分析笔记 | 识别候选 |
| Tag Wrangler | 标签管理 | 标签重构 |
常用脚本集合
查找重复内容
javascript
<%*
// 查找可能重复的笔记
const files = app.vault.getMarkdownFiles();
const duplicates = [];
for (let i = 0; i < files.length; i++) {
for (let j = i + 1; j < files.length; j++) {
const content1 = await app.vault.read(files[i]);
const content2 = await app.vault.read(files[j]);
// 简单的相似度判断
const similarity = calculateSimilarity(content1, content2);
if (similarity > 0.7) {
duplicates.push([files[i].name, files[j].name, similarity]);
}
}
}
console.log("可能重复的笔记:", duplicates);
%>批量创建 MOC
javascript
<%*
// 为每个文件夹创建索引
const folders = app.vault.getAllFolders()
.filter(f => f.path !== "/");
for (const folder of folders) {
const files = app.vault.getMarkdownFiles()
.filter(f => f.parent?.path === folder.path);
if (files.length > 3) { // 超过3个笔记才创建索引
let content = `# ${folder.name} 索引\n\n`;
content += `> 本索引自动生成于 ${tp.date.now("YYYY-MM-DD")}\n\n`;
for (const file of files) {
if (!file.name.startsWith("索引")) {
content += `- [[${file.basename}]]\n`;
}
}
await app.vault.create(`${folder.path}/索引.md`, content);
}
}
%>重组最佳实践
分阶段进行
yaml
重组计划:
第一阶段: 分析现状
- 导出笔记列表
- 识别问题区域
- 制定重组方案
第二阶段: 小范围试点
- 选择一个文件夹
- 执行重组流程
- 验证效果
第三阶段: 批量执行
- 分批次处理
- 定期检查
- 及时调整保持链接完整
yaml
链接维护:
- 使用 Note Composer 自动更新
- 合并后检查断链
- 使用 Dataview 查询孤立笔记备份优先
yaml
安全措施:
- 重组前完整备份
- 使用 Git 版本控制
- 大型重组分步进行
- 保留操作日志常见问题
合并后链接怎么处理?
解决方案
使用 Note Composer 插件会自动更新链接。手动合并时:
- 在原笔记位置创建重定向笔记
- 或使用脚本批量更新链接
- 检查孤立笔记并修复
拆分后如何保持关联?
解决方案
- 创建 MOC 索引笔记
- 在各笔记间添加导航链接
- 使用
up/next/prev属性 - 添加反向链接说明
重构会不会破坏已有工作流?
建议
- 先在测试仓库验证
- 分阶段执行重组
- 保留原结构一段时间
- 逐步过渡到新结构
如何判断哪些笔记需要归档?
判断标准
- 超过 180 天未修改
- 被引用次数少于 2 次
- 项目已完成
- 内容已整合到其他笔记
- 时效性已过