# Обработка больших наборов данных

Каждый Job имеет фиксированный объём локального диска, определяемый его [hardware flavor](./jobs-pricing#pricing) (колонка **Ephemeral Storage**, также отображаемая командой `hf jobs hardware`). Чтобы работать с данными, не обязательно помещать весь датасет на этот диск: датасеты и [Storage Buckets](./storage-buckets) можно читать напрямую из Hub — стримингом, запросами или монтированием — так что один Job способен обрабатывать данные, значительно превышающие объём его диска. На этой странице описаны доступные варианты и случаи, когда стоит использовать каждый из них.

## Какой подход выбрать?

- **Помещается на диск** → обычный вызов `load_dataset(...)` работает как есть (или просто выберите более крупную версию — до 1 ТБ временного диска).
- **Итерация по строкам, обработка или обучение** → [stream](#stream-the-dataset).
- **Фильтрованные или обрезанные по столбцам сканы** → запросите их [напрямую через `hf://`](#read-and-filter-over-hf) с помощью Polars или DuckDB.
- **Инструменты, ожидающие локальные пути к файлам** → [mount](#mount-a-dataset-model-or-bucket) репозитория и чтение по требованию.
- **Сохранение результатов** → записывайте их в [Storage Bucket](#save-results), чтобы они сохранились после завершения Job.

## Потоковая загрузка набора данных

Функция Streaming читает примеры из Hub по мере их потребления вашим кодом — без загрузки и локальной копии, и она масштабируется до датасетов объёмом в несколько ТБ. В последних релизах её [эффективность выросла до 100 раз](https://huggingface.co/blog/streaming-datasets), достигнув производительности, сопоставимой с локальными SSD при обучении на множестве воркеров:

```python
from datasets import load_dataset

ds = load_dataset("HuggingFaceFW/fineweb-edu", "sample-10BT", split="train", streaming=True)
for example in ds.take(1000):
    ...  # streams in as you iterate, nothing hits disk
```

Стримовый датасет — это `IterableDataset` с поддержкой ленивых операций `.filter()`, `.map()`, `.shuffle(buffer_size=...)` и `.batch()`. Его можно напрямую передать в `DataLoader` PyTorch или в `Trainer` для обучения на данных, превышающих объём диска. Полный API описан в [руководстве по стримингу](/docs/datasets/stream), а пошаговые инструкции по обучению в одноузловых и распределённых конфигурациях — в разделе [Примеры и учебные материалы](./jobs-examples).

Стриминг также работает в распределённых конфигурациях с использованием Spark:

```python
import pyspark_huggingface

df = spark.read.format("huggingface").option("config", "sample-10BT").load("HuggingFaceFW/fineweb-edu")
```

Полученный Spark dataframe распределён: каждый воркер читает данные из собственного подмножества файлов. Примеры чтения, записи и эффективной фильтрации строк и столбцов приведены в [документации Spark](./datasets-spark).

## Чтение и фильтрация по `hf://`

Многие библиотеки для работы с данными читают наборы данных Hub напрямую по путям `hf://` — **Polars**, **DuckDB** и **pandas** нативно сканируют Parquet из Hub, перекладывая фильтрацию и выбор столбцов на этап сканирования, благодаря чему одна задача может обработать значительно больше данных, чем помещается в оперативной памяти или на диске. Этот запрос суммирует ~28 ГБ Parquet примерно за четыре минуты на стандартной CPU-версии:

```python
import polars as pl

agg = (
    pl.scan_parquet("hf://datasets/HuggingFaceFW/fineweb-edu/sample/10BT/*.parquet")
    .filter(pl.col("int_score") >= 4)
    .group_by("int_score")
    .agg(pl.len().alias("docs"), pl.col("token_count").sum().alias("tokens"))
    .sort("int_score")
    .collect()
)
print(agg)
```

Сканы такого типа ограничены сетью, а не памятью, и движки различаются по степени агрессивности параллелизации удалённых чтений, поэтому время выполнения зависит от библиотеки. Два практических следствия: установите `--timeout` выше значения по умолчанию 30 минут для длительных сканов и распределите работу между несколькими параллельно выполняемыми Jobs, чтобы ускорить процесс. Примеры для каждой библиотеки приведены в разделах [Polars](./datasets-polars), [DuckDB](./datasets-duckdb) и [pandas](./datasets-pandas), а о чтении **buckets** по `hf://` (через [`HfFileSystem`](/docs/huggingface_hub/guides/hf_file_system)) см. в разделе [Python data tools](./storage-buckets-access#python-data-tools).

## Подключение набора данных, модели или хранилища

Подключите репозиторий или бакет к Job как локальный путь с помощью `-v` / `--volume`; файлы загружаются по мере необходимости по мере чтения кодом, поэтому любой инструмент, работающий с локальными файлами, будет работать без изменений:

```bash
hf jobs uv run --flavor cpu-upgrade \
  -v hf://datasets/HuggingFaceFW/fineweb-edu:/mnt/data \
  process.py
```

```python
# /// script
# dependencies = ["polars"]
# ///
# process.py — the mounted repo is just a directory of files
from pathlib import Path

import polars as pl

for path in Path("/mnt/data/sample/10BT").glob("*.parquet"):
    shard = pl.read_parquet(path)
    ...  # process one shard at a time, write results out
```

Монтирование — естественный выбор, когда файлы используются целиком — веса моделей, аудио- или изображения, архивы — или когда инструмент принимает только пути к файлам. Для больших многофайловых сканирований Parquet запрос [напрямую по `hf://`](#read-and-filter-over-hf) обычно в несколько раз быстрее, чем сканирование через монтирование.

Наборы данных и модели монтируются только для чтения, а бакеты — для чтения и записи, что делает их удобным местом для [сохранения результатов](#save-results). См. [Конфигурация](./jobs-configuration#volumes) для полного синтаксиса `-v` и [паттерны доступа к бакетам](./storage-buckets-access#volume-mounts-in-jobs-and-spaces) для подробностей.

> [!TIP]
> Файлы, читаемые через точку монтирования, кэшируются на эфемерном диске Job, поэтому ленивое чтение (по одному файлу за раз) позволяет удерживать объём занимаемого пространства на низком уровне. При запуске локального скрипта с помощью `hf jobs uv run` каталог скрипта монтируется в `/data`, поэтому монтируйте данные в другое место (например, `/mnt/data`).

## Сохранить результаты

Эфемерный диск не переживает завершение Job, поэтому записывайте всё, что нужно сохранить, в [Storage Bucket](./storage-buckets), смонтированный с правами на чтение и запись, либо отправляйте данные на Hub в виде датасета. DuckDB может фильтровать источник по `hf://` и записывать совпадения напрямую в смонтированный бакет одним запросом вне памяти, поэтому результат не должен помещаться в оперативную память:

```bash
hf jobs uv run --flavor cpu-upgrade --timeout 1h \
  -v hf://buckets/username/my-output:/mnt/out \
  filter.py
```

```python
# /// script
# dependencies = ["duckdb"]
# ///
# filter.py — scan ~28 GB of Parquet, keep only the matching rows
import duckdb

duckdb.sql(
    """
    COPY (
        SELECT text, url, token_count
        FROM 'hf://datasets/HuggingFaceFW/fineweb-edu/sample/10BT/*.parquet'
        WHERE int_score >= 4 AND token_count >= 4000
    ) TO '/mnt/out/result.parquet' (FORMAT parquet)
    """
)
```

Файлы, записанные в путь монтирования бакета, сохраняются после завершения Job. Чтобы опубликовать обработанный датасет, используйте [`Dataset.push_to_hub`](/docs/datasets/upload_dataset).

## Пример: запрос к Common Crawl без его загрузки

Common Crawl зеркалирует свой архив в бакете [`commoncrawl/commoncrawl`](https://huggingface.co/buckets/commoncrawl/commoncrawl) — сотни ТБ. Прочитайте один WET-шард (в формате plaintext) напрямую из `hf://`, распарсите его и выполните запрос с помощью DuckDB; передаётся лишь несколько МБ, так как gzip-файл читается последовательно и чтение останавливается досрочно:

```python
# /// script
# requires-python = ">=3.11"
# dependencies = ["huggingface_hub>=1.9", "fastwarc>=0.15", "duckdb>=1.0"]
# ///
import duckdb
from fastwarc.warc import ArchiveIterator, WarcRecordType
from huggingface_hub import hffs

WET = (
    "buckets/commoncrawl/commoncrawl/crawl-data/CC-MAIN-2026-17/"
    "segments/1775805908305.14/wet/"
    "CC-MAIN-20260410081153-20260410111153-00000.warc.wet.gz"
)

rows = []
with hffs.open(WET, "rb") as f:
    for rec in ArchiveIterator(f, record_types=WarcRecordType.conversion):
        lang = (rec.headers.get("WARC-Identified-Content-Language", "") or "und").split(",")[0]
        rows.append((rec.headers.get("WARC-Target-URI", ""), lang, len(rec.reader.read())))
        if len(rows) >= 5000:
            break

con = duckdb.connect()
con.execute("CREATE TABLE wet(url VARCHAR, lang VARCHAR, n_chars BIGINT)")
con.executemany("INSERT INTO wet VALUES (?,?,?)", rows)
con.sql("SELECT lang, count(*) AS docs FROM wet GROUP BY lang ORDER BY docs DESC LIMIT 10").show()
```

Запустите его командой `hf jobs uv run cc_wet.py` — на стандартном CPU-флейворе выполнение занимает около минуты и выводит:

```
┌─────────┬───────┐
│  lang   │ docs  │
│ varchar │ int64 │
├─────────┼───────┤
│ eng     │  1974 │
│ zho     │   586 │
│ rus     │   434 │
│ jpn     │   244 │
│ …       │    …  │
└─────────┴───────┘
```

## См. также

- [Stream](/docs/datasets/stream) · [Потоковые наборы данных: в 100 раз эффективнее](https://huggingface.co/blog/streaming-datasets)
- [Тарифы и оборудование](./jobs-pricing#pricing) — эфемерный диск для каждого типа · [Конфигурация](./jobs-configuration#volumes) — тома
- [Хранилища](./storage-buckets) · [паттерны доступа](./storage-buckets-access) · [интеграции](./storage-buckets-integrations)

