QMD Search 详解

📋 什么是 QMD Search?

QMD (Query Markdown Document) 是一个基于 RAG (Retrieval-Augmented Generation) 的智能文档查询系统,专为 Markdown 文档库设计。

核心定位

  • 📚 Obsidian/Markdown 文档的语义搜索引擎
  • 🔍 支持关键词匹配 + 语义理解的混合检索
  • 🧠 可选 LLM 增强(Query Expansion + Reranking)
  • 🚀 本地运行,数据完全私有

🏗️ 核心架构

┌─────────────────────────────────────────────────────────┐
│                                                   QMD Search 系统                                                         │
├─────────────────────────────────────────────────────────┤
│  ┌─────────────┐    ┌──────────────┐    ┌────────────┐                   │
│  │  文档索引层            │    │   检索引擎                 │    │  LLM 增强层         │                   │
│  │  - Markdown         │    │  - BM25 FTS5           │    │ - Query                │                  │
│  │  - 分块                   │─▶│  - 向量检索              │─▶│  Expansion         │                   │
│  │  - Embedding│     │      |   - RRF 融合   │          │ - Rerank                   │                   │
│  └─────────────┘    └──────────────┘    └────────────┘                   │
│                          │                                                                                                          │
│                          ▼                                                                                                          │
│                  ┌──────────────┐                                                                              │
│                  │  SQLite 数据库           │                                                                             │
│                  │  - FTS5 全文索引        │                                                                             │
│                  │  - sqlite-vec              │                                                                              │
│                  └──────────────┘                                                                              │
└─────────────────────────────────────────────────────────┘

🔬 工作原理

1️⃣ 文档索引流程

用户添加文档
    │
    ▼
读取 Markdown 文件
    │
    ├──▶ 提取元数据(标题、标签、创建时间)
    │
    ├──▶ 文档分块(Chunking)
    │     - 按段落/标题分割
    │     - 保留上下文继承关系
    │
    ├──▶ 生成 Embedding 向量
    │     - 使用 Sentence Transformers
    │     - 默认模型:all-MiniLM-L6-v2
    │
    └──▶ 存储到数据库
          - 原文 → SQLite FTS5(全文索引)
          - 向量 → sqlite-vec(向量索引)
          - 元数据 → 关系表

2️⃣ 混合检索流程(Hybrid Search)

用户查询:"如何在 Obsidian 中配置同步?"
    │
    ├─────────────────────┬─────────────────────┐
    │                     │                     │
    ▼                     ▼                     ▼
BM25 全文检索        向量语义检索          LLM Query Expansion
(关键词匹配)        (语义相似度)          (可选,扩展查询)
    │                     │                     │
    │ 返回 Top 20         │ 返回 Top 20         │ 生成 3-5 个变体
    │                     │                     │
    └─────────────────────┴─────────────────────┘
                          │
                          ▼
              Reciprocal Rank Fusion (RRF)
              融合两个结果列表
                          │
                          ▼
              Position-Aware Blending
              根据位置调整最终分数
                          │
                          ▼
              LLM Rerank(可选)
              使用 LLM 重新排序 Top 40
                          │
                          ▼
              返回最终 Top 10 结果

🎯 核心算法详解

1. BM25 全文检索

技术栈:SQLite FTS5

-- 查询示例
SELECT 
    d.title,
    d.path,
    bm25(documents_fts, 10.0, 1.0) as bm25_score
FROM documents_fts f
JOIN documents d ON d.id = f.rowid
WHERE documents_fts MATCH 'Obsidian 同步'
ORDER BY bm25_score ASC  -- BM25 分数越低越好(负数)

特点

  • ✅ 精确匹配关键词
  • ✅ 支持布尔逻辑(AND、OR、短语)
  • ✅ 速度快,适合精确查询
  • ❌ 无法理解语义(”同步” ≠ “sync”)

2. 向量语义检索

技术栈:sqlite-vec + Sentence Transformers

# 生成查询向量
query_embedding = model.encode("如何在 Obsidian 中配置同步?")

# 向量相似度搜索(余弦相似度)
SELECT 
    d.title,
    d.path,
    vec_distance_cosine(query_vec, embedding) as similarity
FROM documents d
ORDER BY similarity DESC
LIMIT 20

特点

  • ✅ 理解语义(”同步” ≈ “sync” ≈ “备份”)
  • ✅ 支持跨语言匹配
  • ✅ 能找到相关但关键词不同的文档
  • ❌ 可能遗漏精确匹配

3. RRF (Reciprocal Rank Fusion)

目的:融合 BM25 和向量检索的结果

公式

RRF Score = Σ (1 / (k + rank_i))

其中:
- rank_i = 文档在第 i 个结果列表中的排名
- k = 60(经验值,防止分母过小)

示例

文档 A: BM25 排名 3, 向量排名 5
RRF Score = 1/(60+3) + 1/(60+5) = 0.0159 + 0.0154 = 0.0313

文档 B: BM25 排名 1, 向量排名 15
RRF Score = 1/(60+1) + 1/(60+15) = 0.0164 + 0.0133 = 0.0297

→ 文档 A 排名更高(在两个列表中都表现稳定)

优势

  • ✅ 无需归一化不同分数
  • ✅ 平衡两种检索方式
  • ✅ 对异常值不敏感

4. LLM 增强(可选)

Query Expansion(查询扩展)

# 原始查询
query = "Obsidian 同步配置"

# LLM 生成的变体
expanded_queries = [
    "Obsidian 如何设置自动同步",
    "Obsidian sync configuration",
    "Obsidian 多设备数据同步方法",
    "Obsidian 云端备份设置"
]

# 对每个变体执行检索,合并结果

触发条件

  • 初始检索结果分数较低(< 0.85)
  • 结果分布分散(无明显高分文档)

Rerank(重排序)

# 从混合检索中获取 Top 40 候选
candidates = hybrid_search(query, limit=40)

# 使用 LLM 评估相关性
reranked = llm.rerank(query, candidates)

# 返回 Top 10
return reranked[:10]

常用模型

  • Cohere Rerank
  • BGE Reranker
  • 自定义 LLM(GPT-4、Claude 等)

💻 使用方法

安装

# 使用 pipx 安装(推荐,隔离环境)
pipx install qmd

# 或从源码安装
pip install -e .

基本配置

# 1. 添加文档集合(Collection)
qmd add obsidian-vault --path ~/opt/Obsidian_vault --pattern "*.md"

# 2. 更新索引
qmd update

# 3. 查看状态
qmd status

搜索命令

# 基础搜索
qmd search "如何在 Obsidian 中配置同步"

# 限定集合
qmd search "同步配置" --collection obsidian-vault

# 指定结果数量
qmd search "同步" --limit 5

# 显示完整文档内容
qmd search "同步" --full

# 显示行号
qmd search "同步" --line-numbers

# 输出为 JSON
qmd search "同步" --format json

# 输出为 Markdown
qmd search "同步" --format md

深度搜索(Hybrid + Rerank)

# 使用 query 命令执行深度搜索
qmd query "如何在 Obsidian 中配置同步"

# 等价于
qmd search "如何在 Obsidian 中配置同步" --full --rerank

管理 Collections

# 列出所有集合
qmd list
qmd ls

# 重命名集合
qmd collection rename old-name new-name

# 删除集合
qmd remove collection-name

# 清理数据库(删除孤立向量)
qmd cleanup

文件监听(自动更新索引)

# 启动监听模式
qmd watch

# 监听特定集合
qmd watch --collection obsidian-vault

功能

  • 📝 检测文件新增/修改/删除
  • 🔄 自动更新索引
  • 🚀 实时生效,无需手动 qmd update

⚡ 高效使用技巧

1. 优化查询语句

# ✅ 好的查询
qmd search "Obsidian 同步 配置 多设备"  # 关键词明确
qmd search "如何设置自动备份"           # 自然语言

# ❌ 避免过于宽泛
qmd search "同步"                       # 太短,结果过多
qmd search "配置"                       # 缺少上下文

2. 使用 Collection 过滤

# 工作文档
qmd search "项目规范" -c work-notes

# 个人笔记
qmd search "读书笔记" -c personal

# 技术文档
qmd search "API 设计" -c tech-docs

优势

  • 🎯 缩小搜索范围
  • ⚡ 提升搜索速度
  • 📊 结果更精准

3. 利用标签和元数据

在 Markdown 中使用标准 Frontmatter:

---
created: 2026-04-15
tags: [obsidian, 同步,配置]
category: 技术文档
---

# 文档标题

搜索时

qmd search "tags:obsidian 同步"
qmd search "category:技术文档 配置"

4. 组合使用 BM25 和语义搜索

# 精确匹配优先
qmd search "npm install 命令" --format files

# 语义理解优先
qmd query "怎么安装 Node.js 包"  # 使用 LLM 增强

5. 输出格式选择

# 快速浏览(默认 CLI)
qmd search "同步"

# 获取文件列表(用于脚本)
qmd search "同步" --format files

# 导入到其他工具
qmd search "同步" --format json | jq '.[].file'

# 生成报告
qmd search "同步" --format md > 搜索结果.md

6. 定期维护

# 每周更新索引
qmd update

# 每月清理数据库
qmd cleanup

# 查看索引状态
qmd status

🔧 高级配置

自定义 Embedding 模型

# 编辑配置文件 ~/.config/qmd/config.yaml
embedding:
  model: "BAAI/bge-small-zh-v1.5"  # 中文优化
  dimension: 512

推荐模型

  • 英文:all-MiniLM-L6-v2(快)、bge-large-en(准)
  • 中文:bge-small-zh-v1.5text2vec-base-chinese

调整分块策略

# config.yaml
chunking:
  max_length: 512      # 最大 chunk 长度
  overlap: 50          # 重叠字符数
  by_paragraph: true   # 按段落分割

启用 LLM Rerank

# config.yaml
llm:
  backend: "ollama"
  model: "bge-reranker"
  rerank_top_k: 10

📊 性能优化建议

场景建议
文档库 < 1000 篇默认配置即可
文档库 > 5000 篇使用 --collection 过滤
需要精确匹配优先使用 qmd search
需要语义理解使用 qmd query(带 Rerank)
实时性要求高启用 qmd watch 监听
批量处理使用 --format json 导出

🆚 与其他工具对比

工具优势劣势适用场景
QMD本地运行、支持中文、混合检索需要索引时间Obsidian/Markdown 文档库
Obsidian 内置搜索无需配置、实时仅关键词匹配小型笔记库
Elasticsearch分布式、高性能配置复杂、资源占用高企业级搜索
Algolia云端、开箱即用收费、数据外传SaaS 应用

💡 最佳实践

  1. 定期更新索引 – 设置 cron 任务每天更新
  2. 使用 Collection 分类 – 按主题/项目分离文档
  3. 启用文件监听 – 写作时自动索引
  4. 混合使用 search 和 query – 根据需求选择
  5. 优化 Frontmatter – 添加标签和元数据提升检索精度