Skip to content

Let the caller pick the extractor, and read WET files as a source - #87

Merged
tamnd merged 1 commit into
mainfrom
extractor-flag
Aug 10, 2026
Merged

tamnd merged 1 commit into
mainfrom
extractor-flag

Conversation

@tamnd

@tamnd tamnd commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Closes #49.

markdown export hardcoded h2m with trafilatura in FavorRecall mode. Which extractor you use is a corpus quality decision, not a build time constant, so it is a flag now.

What changed

--extractor h2m|readability|raw|wet on markdown export, and the three WARC engines on markdown refetch. The readability engine was already written and stranded in markdown_bench_test.go where only the benchmark could reach it, so it moved into ccrawl/extractor.go next to the others. raw renders the whole document with no extraction at all, which is the control corpus: every extractor is a lossy judgement about what a page was for, and the output alone never says where that judgement went wrong.

--source-kind warc|wet picks the manifest. It defaults to whatever the extractor needs, so it rarely has to be given, and a pairing that cannot work is a usage error rather than a silently reinterpreted run. A WET file holds no HTML and a WARC holds no pre-extracted text. wet on refetch is rejected too: a live fetch returns HTML, and there is no Common Crawl text to pass through.

Rows carry a new extractor column as name@version, and the dataset card names the engine in its processing steps. The version is the part that matters, since extraction changes between releases and a dataset that only records h2m cannot explain why two shards built months apart disagree about the same page. The WET text has no version of ours to record, so it is stamped with the crawl as wet@CC-MAIN-2026-30.

open-markdown-v3 now has three appended columns (language, language_confidence, extractor) and changes nothing else, so a v2 reader is unaffected.

Done when

  • the same shard exported with three extractors gives three parquet files with identical doc_id sets and different markdown
  • the dataset card says which engine produced the data

Real data

Shard 0 of CC-MAIN-2026-30, the same 3.5 GB of HTML through each engine on the same machine:

Engine Rows Markdown Parquet Mean doc Wall clock
h2m 20861 91.9 MB 46.8 MB 3990 B 1m49s
readability 20666 108.5 MB 51.8 MB 4865 B 1m58s
raw 20806 446.2 MB 328.2 MB 20724 B 2m55s
wet 21165 161.9 MB 80.0 MB 6604 B 15s

20353 documents are in all three WARC engines, 97.6 percent of what h2m produced, and of the documents h2m and readability share only 284 have byte identical text. So the first box holds with one honest caveat worth stating rather than hiding: the doc_id sets are not exactly identical, because an engine that extracts nothing from a page skips it instead of writing an empty row, and the engines do not give up on quite the same pages. Row counts reproduced exactly across two runs of the same shard.

raw produces roughly five times the text of h2m from the same pages, which is a fair measure of how much of a web page is not the page. wet is in a different cost class, and it is also somebody else's extraction decision, boilerplate included, in plain text rather than Markdown.

Fixed on the way past

The refetch flag checks ran after the manifest download, so a rejected flag combination cost a network round trip before it was rejected. They run before anything is fetched now. And the source-kind mismatch error started with a flag name, which the error renderer title-cases into Source-Kind, so it is worded from the extractor instead.

Gates

gofmt -l ., go vet ./..., go test ./..., golangci-lint run (0 issues), ./scripts/docs-drift.sh (reference matches the binary).

markdown export hardcoded h2m with trafilatura in FavorRecall mode. Which
extractor you use is a corpus quality decision, not a build time constant: the
same shard through two engines is two different corpora, and the only way to
find out which one suits a downstream task is to build both and compare.

--extractor takes h2m, readability, raw, or wet. The readability engine was
already written, sitting in markdown_bench_test.go where nothing but the
benchmark could reach it, so it moved into ccrawl/extractor.go next to the
others. raw renders the whole document with no extraction at all, which sounds
useless and is not: every extractor is a lossy judgement about what a page was
for, and raw is the control you measure that judgement against.

wet is a different kind of source. Common Crawl already extracted text into the
WET files, pkg/wet has read them since v0.4.0, and no pipeline published them.
--source-kind picks the manifest, defaults to whatever the extractor needs, and
refuses a pairing that cannot work rather than silently reinterpreting the run.
A WET file holds no HTML and a WARC holds no pre-extracted text.

Every row now carries an extractor column as name@version, and the dataset card
names the engine in its processing steps. The version is the part that matters:
extraction changes between releases, and a dataset that only records "h2m"
cannot explain why two shards built months apart disagree about the same page.
The WET text is Common Crawl's own with no version of ours to record, so it is
stamped with the crawl instead.

Measured on shard 0 of CC-MAIN-2026-30, the same 3.5 GB of HTML each time:

  h2m          20861 rows   91.9 MB md   1m49s
  readability  20666 rows  108.5 MB md   1m58s
  raw          20806 rows  446.2 MB md   2m55s
  wet          21165 rows  161.9 MB md      15s

20353 documents are in all three WARC engines, 97.6 percent of what h2m
produced, and of the ones h2m and readability share only 284 have byte
identical text. The row counts differ because an engine that extracts nothing
skips the page rather than writing an empty row, and the engines do not give up
on quite the same pages.

Two things fixed on the way past. The refetch flag checks ran after the manifest
download, so a rejected flag combination cost a round trip first; they run
before anything is fetched now. And the source-kind mismatch error started with
a flag name, which the error renderer title-cases into "Source-Kind", so it is
worded from the extractor instead.

Closes #49
@tamnd tamnd added this to the v0.8.0 milestone Aug 10, 2026
@tamnd tamnd added priority: P1 Corpus work, needed by the gao program type: feature New capability area: pipeline Publish and export pipelines labels Aug 10, 2026
@tamnd
tamnd merged commit 637a784 into main Aug 10, 2026
7 of 8 checks passed
@tamnd
tamnd deleted the extractor-flag branch August 10, 2026 07:16
@github-actions github-actions Bot mentioned this pull request Aug 10, 2026
7 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: pipeline Publish and export pipelines priority: P1 Corpus work, needed by the gao program type: feature New capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E17: let the caller pick the extractor, and add a WET source

1 participant