Skip to content

feat(crawler): git ライクな世代管理(commit graph + content-addressable storage)の導入 #23

Description

@YusukeHirao

概要

既存の .nitpicker アーカイブに対して再クロールで更新する機能を、単なる「上書き(upsert)」ではなく 1つの .nitpicker ファイル内に git ライクな世代管理(commit graph)を持たせる形で導入する。

定期監査のワークフローでは「前回からサイトのどこがどう変わったか」を継続的に追えることが本質的な価値になる。一方向の上書き更新では履歴が残らず、分析結果も破棄され、差分も取れない。そこで内部 DB に content-addressable storage + commit graph を導入し、クロールのたびに世代(commit)を積み上げられるアーキテクチャを目指す。

背景・動機

  • 大規模サイトのクロールは時間がかかるため、変更があったページだけを効率的に更新したい
  • 定期監査で「前回アーカイブをベースに差分更新 → 何が変わったかを提示」できると運用価値が大きい
  • 単純な上書きでは①履歴が残らない ②分析結果が毎回破棄される ③差分が取れない、という問題がある
  • --resume(中断再開)/ --append(スコープ拡張)は既にあるが、「完了済みアーカイブの世代更新」は未対応

ゴール(4つを同時に満たす)

  1. 再クロールの時間短縮 — 変更ページだけを効率的に更新する
  2. ストレージ削減 — 未変更の HTML / リソースを世代間で重複保存しない
  3. 変更内容の監査・可視化 — 前回世代からどのページの何が変わったか(追加 / 削除 / 変更)を提示する
  4. 分析結果の世代保持 — analyze プラグイン結果を commit ごとに保持し、世代間で比較できる

アーキテクチャ・コンセプト

「git for data」の核心アルゴリズムである Prolly Tree(probabilistic B-tree、Merkle Tree と B-tree のハイブリッド。Noms 発祥 / Dolt が採用)本質だけを SQLite 上に軽量実装する。フルエンジンの自作(Dolt は Go 製で移植非現実的)は nitpicker の規模(数万ページ)には過剰なため採らない。

採り入れる本質:

  • Content-addressable storage — HTML スナップショット等を内容ハッシュ(SHA-256)でアドレス化し、未変更分は1度だけ保存する(= 構造共有 / dedup)
  • 履歴独立性 — 行の論理内容から決定的に算出するハッシュ(rowHash)。挿入順や内部 ID に依らず、同じ内容なら常に同じハッシュ
  • Commit graph — 1クロール = 1 commit。親リンクで世代を連鎖させ、.nitpicker 1ファイル内に完結
  • 差分rowHash の SQL 集合演算(EXCEPT / JOIN)で added / removed / modified を算出。数万ページ規模なら full-scan diff で十分

比較検討した他系譜(lakeFS / DVC / MatrixOne)も「内容ハッシュで dedup + 世代参照」という同じ核を持つ。SQLite はネイティブの temporal table を持たないため、世代管理は専用テーブルで実装する。

ユーザーインターフェース(コンセプト)

  • crawl --update <archive> — 既存アーカイブを再クロールし、in-place 上書きではなく新しい commit を積む
  • nitpicker log <archive> — 世代(commit)の履歴を表示
  • nitpicker diff <archive> <commitA> <commitB> — 世代間のページ / リソースの差分(追加 / 削除 / 変更)を表示
  • analyze / report — 世代(commit)を指定して実行・比較

既存コマンドとの整理

  • --append = スコープ拡張(同一世代内で起点 URL を追加)
  • --resume = 中断したクロールの再開
  • --update = 同一スコープの新しい世代を生成(本 issue)

この3つの意図を明確に分離する。既存の --diff(2つの別ファイルを比較し URL リストを txt 出力)は、単一ファイル内 2 commit を比較する nitpicker diff を主経路としつつ「2アーカイブ比較」として整理する。

段階導入の方針

履歴のない単純な dedup から始め、MVP を積み上げる:

  1. content-addressable な blob 化 + dedup(commit graph なし・完全後方互換で単独出荷可。ストレージ削減を先に実現)
  2. commit graph + crawl --update(世代の積み上げ)
  3. nitpicker log / nitpicker diff(差分・履歴の可視化)
  4. analyze 結果の世代保持(commit ごとの分析結果の保持・比較)
  5. (任意)GC(到達不能 blob の prune)、HTML 本文の行 diff

補足

  • 本リポジトリは v0.x のため .nitpicker フォーマットの破壊的変更・migration は許容(既存アーカイブの移行は不要)
  • 詳細なスキーマ設計・実装手順は別途実装フェーズで詰める。本 issue はコンセプトの確定が目的

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions