From 359acc3c0b892524af77e05f73cec5b4ebc301d7 Mon Sep 17 00:00:00 2001 From: Yusuke Hirao Date: Tue, 14 Jul 2026 13:13:40 +0900 Subject: [PATCH] feat(page-cluster)!: trim options, add CLI and onProgress, cut public API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: the `mergeRareLandmarkClusters`, `landmarkRarityThreshold`, `landmarkGateSimilarityThreshold`, and `autoCapMainDepth` options are removed from `resolvePageClusterKeys`. The `autoCapMainDepth`-driven
depth cap is now unconditional and matches the previous default (`true`); the rare-landmark merge feature was never validated on real crawl data and is dropped along with its `mergeLandmarkAffinedClusters` implementation. BREAKING CHANGE: `package.json` `exports` shrinks from 17 subpaths to 4 (`.` / `./extract-landmarks` / `./resolve-landmark-variant-keys` / `./resolve-page-cluster-keys`). Internal helpers stay in `src/` for in-package imports; downstream callers relying on removed subpaths must build against the public surface. New: - `bin: page-cluster` CLI. JSONL in, JSONL out, single `--content-block- attribute` flag, `--help` / `--version`, stderr progress lines. Uses Node standard APIs only. - `resolvePageClusterKeys` `onProgress` callback + `ProgressEvent` discriminated union covering pass0 / pass1 / pass1b / stage-b start. - `derivePathClusterKeys` — auto-cut-driven URL-path depth selector. Exported as a building block and reachable via `resolveBlockingGroupKeys`'s new `pathDepth: 'auto'`; `resolvePage- ClusterKeys` continues to use static depth 1 for now (opt-in staging, same as previous auto-cut adoptions). - `@example` blocks on the 4 public APIs. - Rewritten README aimed at external users, CLI-first. Co-Authored-By: Claude Opus 4.7 --- packages/@d-zero/page-cluster/README.md | 123 +-- packages/@d-zero/page-cluster/package.json | 59 +- .../src/canonicalize-token-set.ts | 4 +- packages/@d-zero/page-cluster/src/cli.spec.ts | 210 ++++++ packages/@d-zero/page-cluster/src/cli.ts | 309 ++++++++ .../src/derive-path-cluster-keys.spec.ts | 54 ++ .../src/derive-path-cluster-keys.ts | 118 +++ .../merge-landmark-affined-clusters.spec.ts | 450 ----------- .../src/merge-landmark-affined-clusters.ts | 706 ------------------ .../page-cluster/src/pass0-blocking.ts | 12 +- .../src/per-page-landmark-signatures.ts | 2 - .../src/resolve-blocking-group-keys.ts | 35 +- .../src/resolve-landmark-variant-keys.ts | 6 + ...esolve-page-cluster-keys-streaming.spec.ts | 24 - .../src/resolve-page-cluster-keys.spec.ts | 176 +---- .../src/resolve-page-cluster-keys.ts | 130 ++-- .../page-cluster/src/stage-a-per-block.ts | 6 +- packages/@d-zero/page-cluster/src/tokenize.ts | 6 + 18 files changed, 916 insertions(+), 1514 deletions(-) create mode 100644 packages/@d-zero/page-cluster/src/cli.spec.ts create mode 100644 packages/@d-zero/page-cluster/src/cli.ts create mode 100644 packages/@d-zero/page-cluster/src/derive-path-cluster-keys.spec.ts create mode 100644 packages/@d-zero/page-cluster/src/derive-path-cluster-keys.ts delete mode 100644 packages/@d-zero/page-cluster/src/merge-landmark-affined-clusters.spec.ts delete mode 100644 packages/@d-zero/page-cluster/src/merge-landmark-affined-clusters.ts diff --git a/packages/@d-zero/page-cluster/README.md b/packages/@d-zero/page-cluster/README.md index b3db0439..0eeee5cb 100644 --- a/packages/@d-zero/page-cluster/README.md +++ b/packages/@d-zero/page-cluster/README.md @@ -1,70 +1,109 @@ # `@d-zero/page-cluster` -大量クローリングした HTML の重複・類似ページ検出のためのパッケージ。`tokenize()` は `` 配下のHTMLを、テキストを除去した構造トークンに変換する。用途・設計判断のWHYは `src/tokenize.ts` の JSDoc を参照。 +大量クロール HTML の重複・類似ページを構造トークンで検出するパッケージ。CLI が主、ライブラリ関数群がオマケ。 -## Installation +## What this does + +`page-cluster` は HTML ページ集合を受け取って、**同一テンプレートと判定できるページ**に同じキーを振る。テキストは無視して DOM 構造だけを見るので、記事本文が違うが同じテンプレートを使うページ群は 1 つのクラスタにまとまる。単一サイトで数万〜十数万ページ規模のクロール成果物を、テンプレート単位に畳んで概観したいときに使う。 + +## Install ```sh yarn add @d-zero/page-cluster ``` -## Usage +インストールすると `page-cluster` コマンドが `node_modules/.bin/` 配下に入る。 + +## Quickstart (CLI) -```ts -import { tokenize } from '@d-zero/page-cluster'; +**入力**: JSONL 1 行 1 ページ。フィールドは以下。`html` 以外はすべて任意(`paths` / `stylesheetHrefs` がないと粗い分類になる)。 -const { tokens, bodyClassList } = tokenize( - '
  • A
  • B
', -); -// tokens: ["body>.card>ul>li", "body>.card>ul>li"] -// bodyClassList: ["law-page"] +```json +{ + "id": "任意の識別子", + "html": "...", + "paths": ["news", "1"], + "stylesheetHrefs": ["/a.css"], + "host": "example.com" +} ``` -### オプション +**出力**: JSONL 1 行 1 ページ、入力順。 -```ts -tokenize(html, { - filterNoiseClasses: true, // 既定値。ハッシュ的自動生成class名を除外する - includeComments: false, // 既定値。コメントノードをトークン化しない -}); +```json +{ "id": "任意の識別子", "clusterKey": "..." } ``` -### クラスタリング +### クローラ出力(JSON 配列)を JSONL に変換して食わせる -クロールしたページ群から最終的なクラスタキーを得るには `resolvePageClusterKeys()` を使う。ブロッキング(URLパス/スタイルシートによる粗い絞り込み)と構造クラスタリング(ブロック内でのcomplete-linkage階層的クラスタリング)を内部で連結し、ブロックを跨いで一意なキーを返す。既定で各ページのランドマーク要素(`
`/`