Precomputed Tags:用預計算索引取代動態搜尋的標籤系統
在設計 VibeBlog 的標籤系統時,我遇到了一個關鍵問題:如何在不使用資料庫的情況下,實現高效能的標籤分類瀏覽?
傳統的 CMS 做法是:每次請求時動態掃描所有文章,然後用 for-loop 過濾出符合標籤的文章。但這種做法有幾個問題:
- ❌ 每次請求都要掃描整個 content 資料夾
- ❌ 需要動態計算,無法充分利用 SSG 的優勢
- ❌ 文章數量增加時效能會線性下降
- ❌ 不適合 CDN 快取
於是,我選擇了 Precomputed Tags(預計算標籤) 架構。
什麼是 Precomputed Tags?
Precomputed Tags 的核心概念是:在 build 時就把所有分類關係計算好,存成靜態 JSON 檔案,前端只需要讀取,零計算。
這就像圖書館的索引卡片系統:
- 傳統方式:每次有人問「有哪些關於 LLM 的書?」,圖書館員就要跑遍整個圖書館去找
- Precomputed 方式:圖書館已經準備好索引卡片,直接翻到「LLM」那一頁,上面列好了所有相關書籍的編號
資料結構設計
1. 文章 Metadata(每篇文章一份 JSON)
每篇文章在 content/meta/ 目錄下都有一份對應的 JSON 檔案:
content/meta/how-i-use-vllm.json
{
"slug": "how-i-use-vllm",
"title": "我怎麼在本機用 vLLM 玩 7B 模型",
"date": "2025-12-02",
"tags": ["LLM", "vLLM", "本地部署", "實驗筆記"],
"summary": "紀錄我怎麼在家用單張 GPU 跑 vLLM 的過程。",
"heroImage": "/images/2025-12-02-vllm-hero.png"
}
標籤就存在這裡的 tags 陣列中。
2. 預計算的標籤索引(tags.json)
在 content/indexes/tags.json 中,我們預先建立好「標籤 → 文章 slug 列表」的映射:
content/indexes/tags.json
{
"LLM": ["how-i-use-vllm", "llm-metrics", "runtime-benchmark"],
"SvelteKit": ["vibeblog-infra", "routing-idea"],
"AI-Blogging": ["ai-html-pipeline", "meta-generator"]
}
這個檔案在 build 前由腳本自動生成,不需要手動維護。
實作方式
生成 tags.json 的腳本
我寫了一個簡單的 Node.js 腳本來掃描所有 meta JSON 檔案,自動生成索引:
scripts/generate-tags-index.ts
// 掃描所有 meta 文件
for (const file of jsonFiles) {
const meta = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
// 將文章 slug 加入對應的 tag
for (const tag of meta.tags) {
if (!tagsIndex[tag]) {
tagsIndex[tag] = [];
}
tagsIndex[tag].push(meta.slug);
}
}
// 寫入 tags.json
fs.writeFileSync('content/indexes/tags.json',
JSON.stringify(tagsIndex, null, 2));
執行 npm run generate:tags 就能更新索引。
SvelteKit 端:只讀取,不計算
在 SvelteKit 的 server load 函數中,我們只需要讀取預計算好的 JSON:
// src/routes/tags/[tag]/+page.server.ts
import { getTagsIndex, getPostMeta } from '$lib/content';
export const load = ({ params }) => {
const tagsIndex = getTagsIndex(); // 讀取預計算的 JSON
const slugs = tagsIndex[params.tag] || [];
// 只讀取需要的文章 meta,不需要掃描全部
const posts = slugs.map(slug => getPostMeta(slug));
return { tag: params.tag, posts };
};
完全零動態計算,純資料查表(O(1))。
與 AI Pipeline 的完美整合
這個架構特別適合 AI 自動化的內容生產流程:
raw 文章
→ AI 處理
→ processed HTML(AI 排版的 HTML)
→ meta JSON(AI 生成的 metadata,包含 tags)
→ 執行 generate:tags 腳本
→ tags.json 自動更新
→ build → deploy
AI 在生成文章時,可以同時:
- 分析文章內容,自動產生相關標籤
- 生成 meta JSON(包含 tags 陣列)
- 生成 processed HTML
然後執行一次 npm run generate:tags,所有分類索引就自動更新了。
優點總結
✅ 效能極高
- 所有分類在 build 時完成
- 前端只讀取 JSON,零計算
- 完美搭配 SSG + CDN
✅ 完全可版本控制
- 分類是檔案,commit 可看變動
- 所有內容都是檔案,易於追蹤
✅ 適合大量文章
- 幾百篇、幾千篇文章也沒差
- 查詢複雜度是 O(1),不會隨文章數量增加而變慢
✅ 適合 AI 自動化
- AI 直接產出分類資料結構
- 不需要複雜的資料庫 schema
- 所有邏輯在 build 前跑完
✅ 與「文章由 AI 生成」的概念超契合
- AI 產文章時同步決定標籤
- 自動更新 tags.json
- 完全自動化的內容管理流程
實際應用
在 VibeBlog 中,這個架構實現了:
/tags- 所有標籤一覽(從 tags.json 讀取)/tags/LLM- 所有 LLM 相關文章(O(1) 查詢)- 文章列表頁面顯示標籤(從 meta JSON 讀取)
- 文章詳情頁面顯示標籤(可點擊跳轉到標籤頁)
所有這些功能都是零運行時計算,純靜態資料。
擴展性
這個模式可以輕鬆擴展到其他分類方式:
content/indexes/years.json- 按年份分類content/indexes/categories.json- 按類別分類content/indexes/authors.json- 按作者分類
只需要在 build 前生成對應的索引檔案,SvelteKit 端就能直接使用。
結論
Precomputed Tags 架構證明了:不需要資料庫,不需要動態查詢,用檔案 + 預計算就能實現高效能的標籤系統。
這種方法特別適合:
- 靜態網站生成(SSG)
- AI 自動化的內容生產
- 需要版本控制的內容管理
- 追求極致效能的部落格系統
在 VibeBlog 的實作中,這個架構不僅解決了標籤分類的問題,更成為整個 AI-First 內容管理系統的基礎。
如果你也在建立類似的系統,不妨試試 Precomputed Tags 架構,你會發現它比傳統的動態搜尋方式更簡單、更快、更可控。