Summary
instance_tier will gain four explicit values:
| value |
strata filled |
status |
human_reviewed |
human Swiss-Prot |
implemented |
human_any_review_status |
+ human TrEMBL |
being implemented |
all_species_reviewed |
+ non-human Swiss-Prot |
being implemented |
all_species_any_review_status |
+ all TrEMBL |
not implemented — this issue |
The first three fit the current architecture. The fourth does not, and the reason is
worth writing down so the next attempt does not start by trying it the easy way.
Why the fourth does not fit
ppi-splitting-pipeline's bin/fetch_domains.py builds the protein universe by
parsing a UniProt flat file fully into RAM:
universe = parse_uniprot_dat(iter_gzip_lines(fh), taxa_filter) # {acc: (taxon, seq)}
then streams Pfam-A.regions.tsv.gz and looks each region's parent up in that dict.
Sizes (UniProt release 2026_03):
| file |
size (gz) |
entries |
uniprot_sprot.dat.gz |
667 M |
~573 k |
uniprot_trembl.dat.gz |
110 G |
~250 M |
all_species_reviewed holds ~573 k proteins — roughly 1 GB of Python strings, which
works. all_species_any_review_status would hold ~250 M, which is hundreds of GB. It
is not a tuning problem.
content_digest() is a second, independent wall: it sorts and joins every accession
in the universe to build the cache key (0.3 s at 573 k). At 250 M that is minutes of
CPU and tens of GB of transient string.
What implementing it actually requires
Not a bigger machine — a different join strategy. Sketch:
- Build a cached accession index over the full TrEMBL DAT, once per UniProt
release: accession -> (taxon_id, reviewed, byte_offset). ~250 M rows; on disk
(SQLite / LMDB / sorted binary), not in RAM. This is the expensive step (~110 GB
streamed once) and it is exactly what the interpro_cache is for.
- Tier-assign during the regions pass using that index, so stratification stays
correct — a family that has a human member must still get it, which a
"sample first, resolve taxon later" shortcut cannot guarantee.
- Fetch sequences only for the sampled instances, by seeking to the recorded
offsets. Sampled set is bounded by ddi_examples_target * ddi_examples_pool_factor * n_families (currently 25 x ~20 k = ~500 k), so this stays small.
- Replace
content_digest() with an order-independent accumulator (XOR/sum of
per-accession hashes) or with a release-string + file-size digest.
- Bump
FORMAT_VERSION again.
Disk budget is not the constraint (cache is provisioned at 1 TB; 110 GB TrEMBL +
4.7 GB regions + a ~150 GB STRING working set still fits).
Where the code lives
- Instance sampling and the universe:
bin/fetch_domains.py in
bionetslab/ppi-splitting-pipeline (vendored here as
subworkflows/external/ppi-splitting, read-only).
- The
instance_tier / uniprot_dat_urls parameter surface, bin/parse_swissprot_dat.py
and the workflow guards: this repo.
Both halves are needed: parse_swissprot_dat.py also parses the flat files, to fill
protein.sequence, protein_go_terms and the STRING id map, and has the same
streaming problem at full-TrEMBL scale.
Summary
instance_tierwill gain four explicit values:human_reviewedhuman_any_review_statusall_species_reviewedall_species_any_review_statusThe first three fit the current architecture. The fourth does not, and the reason is
worth writing down so the next attempt does not start by trying it the easy way.
Why the fourth does not fit
ppi-splitting-pipeline'sbin/fetch_domains.pybuilds the protein universe byparsing a UniProt flat file fully into RAM:
then streams
Pfam-A.regions.tsv.gzand looks each region's parent up in that dict.Sizes (UniProt release 2026_03):
uniprot_sprot.dat.gzuniprot_trembl.dat.gzall_species_reviewedholds ~573 k proteins — roughly 1 GB of Python strings, whichworks.
all_species_any_review_statuswould hold ~250 M, which is hundreds of GB. Itis not a tuning problem.
content_digest()is a second, independent wall: it sorts and joins every accessionin the universe to build the cache key (0.3 s at 573 k). At 250 M that is minutes of
CPU and tens of GB of transient string.
What implementing it actually requires
Not a bigger machine — a different join strategy. Sketch:
release:
accession -> (taxon_id, reviewed, byte_offset). ~250 M rows; on disk(SQLite / LMDB / sorted binary), not in RAM. This is the expensive step (~110 GB
streamed once) and it is exactly what the
interpro_cacheis for.correct — a family that has a human member must still get it, which a
"sample first, resolve taxon later" shortcut cannot guarantee.
offsets. Sampled set is bounded by
ddi_examples_target * ddi_examples_pool_factor * n_families(currently 25 x ~20 k = ~500 k), so this stays small.content_digest()with an order-independent accumulator (XOR/sum ofper-accession hashes) or with a release-string + file-size digest.
FORMAT_VERSIONagain.Disk budget is not the constraint (cache is provisioned at 1 TB; 110 GB TrEMBL +
4.7 GB regions + a ~150 GB STRING working set still fits).
Where the code lives
bin/fetch_domains.pyinbionetslab/ppi-splitting-pipeline(vendored here assubworkflows/external/ppi-splitting, read-only).instance_tier/uniprot_dat_urlsparameter surface,bin/parse_swissprot_dat.pyand the workflow guards: this repo.
Both halves are needed:
parse_swissprot_dat.pyalso parses the flat files, to fillprotein.sequence,protein_go_termsand the STRING id map, and has the samestreaming problem at full-TrEMBL scale.