> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Каталог SeaweedFS

> В этом руководстве описано, как выполнять запросы к данным с помощью ClickHouse и каталога SeaweedFS Iceberg.

export const ExperimentalBadge = () => {
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#experimental-features" className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            Экспериментальная возможность
        </a>;
};

<ExperimentalBadge />

<Note>
  Интеграция с каталогом SeaweedFS работает только с таблицами Iceberg.
</Note>

ClickHouse поддерживает интеграцию с несколькими каталогами (Unity, Glue, REST, Polaris и т. д.). В этом руководстве описано, как запрашивать данные с помощью ClickHouse и каталога [SeaweedFS](https://github.com/seaweedfs/seaweedfs).

SeaweedFS — это распределённое хранилище файлов и объектов с открытым исходным кодом и S3-совместимым шлюзом. Его S3-бакеты таблиц включают оба компонента развертывания Iceberg: встроенный REST-каталог Iceberg предоставляет метаданные таблиц, а бакет таблиц хранит данные таблиц в виде файлов Parquet по той же конечной точке S3:

* **Единый сервис** — метаданные каталога и данные Parquet обслуживаются одним процессом без отдельной базы данных метаданных
* Соответствие **REST API** спецификации REST-каталога Iceberg
* **Обслуживание на стороне сервера** — автоматическая компактация файлов Parquet и удаление устаревших снимков без внешнего сервиса обслуживания

<Note>
  Поскольку эта возможность экспериментальная, её необходимо включить с помощью:
  `SET allow_experimental_database_iceberg = 1;`
</Note>

<div id="local-development-setup">
  ## Настройка локальной среды разработки
</div>

Для локальной разработки и тестирования SeaweedFS и ClickHouse можно запустить с помощью Docker Compose. Этот подход идеально подходит для обучения, прототипирования и разработки.

<div id="local-prerequisites">
  ### Предварительные требования
</div>

1. **Docker и Docker Compose**: убедитесь, что Docker установлен и запущен.
2. **Версии**: SeaweedFS 4.42 или новее; ClickHouse 26.8 или новее (версии начиная с 25.8 поддерживают чтение и вставку, но для создания таблиц через каталог требуется версия 26.8).
3. **Python с PyIceberg** (необязательно): используется ниже для заполнения демонстрационных данных.

<div id="setting-up-local-seaweedfs-catalog">
  ### Настройка локального каталога SeaweedFS
</div>

**Шаг 1:** Создайте папку для запуска примера, затем создайте файл `s3config.json` с учётными данными для шлюза S3 и каталога:

```json theme={null}
{
  "identities": [
    {
      "name": "analyst",
      "credentials": [
        {
          "accessKey": "tutorialkey",
          "secretKey": "tutorialsecret"
        }
      ],
      "actions": ["Admin", "Read", "Write", "List", "Tagging"]
    }
  ]
}
```

**Шаг 2:** Создайте файл `docker-compose.yml` со следующей конфигурацией:

```yaml theme={null}
services:
  seaweedfs:
    image: chrislusf/seaweedfs:latest
    command: mini -dir=/data -s3.config=/etc/seaweedfs/s3config.json -tableBucket=analytics
    ports:
      - "8333:8333"   # S3 endpoint
      - "8181:8181"   # Iceberg REST catalog
    volumes:
      - ./s3config.json:/etc/seaweedfs/s3config.json
      - seaweedfs_data:/data
    networks:
      - iceberg_net

  clickhouse:
    image: clickhouse/clickhouse-server:latest
    container_name: seaweedfs-clickhouse
    ports:
      - "8123:8123"
      - "9000:9000"
    depends_on:
      - seaweedfs
    networks:
      - iceberg_net

volumes:
  seaweedfs_data:

networks:
  iceberg_net:
    driver: bridge
```

Команда `mini` запускает весь стек SeaweedFS в одном контейнере. Флаг `-tableBucket=analytics` заранее создаёт бакет S3 Tables с именем `analytics`, который используется в качестве хранилища Iceberg.

**Шаг 3:** Выполните следующую команду, чтобы запустить сервисы:

```bash theme={null}
docker compose up -d
```

<div id="seeding-sample-data">
  ### Заполнение тестовыми данными
</div>

Каталог изначально пуст. Создайте таблицу и добавьте в неё несколько строк с помощью PyIceberg (`pip install pyiceberg pyarrow`):

```python theme={null}
import pyarrow as pa
from pyiceberg.catalog.rest import RestCatalog

catalog = RestCatalog(
    "seaweedfs",
    uri="http://localhost:8181",
    warehouse="s3://analytics",
    credential="tutorialkey:tutorialsecret",
    **{
        "s3.endpoint": "http://localhost:8333",
        "s3.access-key-id": "tutorialkey",
        "s3.secret-access-key": "tutorialsecret",
        "s3.region": "us-east-1",
        "s3.path-style-access": "true",
    },
)

rows = pa.table({
    "id": pa.array([1, 2, 3, 4, 5, 6], pa.int64()),
    "region": ["NA", "EU", "EU", "APAC", "NA", "EU"],
    "amount": pa.array([12.5, 40.0, 7.25, 99.9, 3.5, 61.0], pa.float64()),
})

catalog.create_namespace("sales")
table = catalog.create_table("sales.orders", schema=rows.schema)
table.append(rows)
```

<div id="connecting-to-local-seaweedfs-catalog">
  ### Подключение к локальному каталогу SeaweedFS
</div>

Подключитесь к контейнеру ClickHouse:

```bash theme={null}
docker exec -it seaweedfs-clickhouse clickhouse-client
```

Затем создайте подключение к каталогу SeaweedFS:

```sql theme={null}
SET allow_experimental_database_iceberg = 1;

CREATE DATABASE lake
ENGINE = DataLakeCatalog('http://seaweedfs:8181/v1', 'tutorialkey', 'tutorialsecret')
SETTINGS catalog_type = 'rest',
    warehouse = 's3://analytics',
    storage_endpoint = 'http://seaweedfs:8333/analytics',
    catalog_credential = 'tutorialkey:tutorialsecret',
    oauth_server_uri = 'http://seaweedfs:8181/v1/oauth/tokens'
```

Аргументы движка содержат учетные данные S3, которые ClickHouse использует для чтения данных таблицы, а `catalog_credential` и `oauth_server_uri` используются для аутентификации в самом каталоге по потоку OAuth2 Client Credentials. SeaweedFS принимает один и тот же ключ доступа и секретный ключ в обоих случаях.

<div id="querying-seaweedfs-catalog-tables-using-clickhouse">
  ## Выполнение запросов к таблицам каталога SeaweedFS в ClickHouse
</div>

Теперь, когда соединение установлено, можно выполнять запросы к каталогу SeaweedFS. Например:

```sql theme={null}
USE lake;

SHOW TABLES;
```

```response theme={null}
┌─name─────────┐
│ sales.orders │
└──────────────┘
```

<Info>
  **Требуются обратные кавычки**

  Обратные кавычки требуются, поскольку ClickHouse не поддерживает более одного пространства имен.
</Info>

Чтобы выполнить запрос к таблице:

```sql theme={null}
SELECT region, sum(amount) AS total
FROM `sales.orders`
GROUP BY region
ORDER BY total DESC;
```

```response theme={null}
┌─region─┬──total─┐
│ EU     │ 108.25 │
│ APAC   │   99.9 │
│ NA     │     16 │
└────────┴────────┘
```

<div id="creating-tables-and-writing-data-from-clickhouse">
  ## Создание таблиц и запись данных из ClickHouse
</div>

Вы также можете создавать таблицы в каталоге SeaweedFS и записывать в них данные непосредственно из ClickHouse:

```sql theme={null}
SET allow_experimental_database_iceberg = 1;
SET allow_experimental_insert_into_iceberg = 1;
SET write_full_path_in_iceberg_metadata = 1;

CREATE TABLE lake.`sales.returns` (id Int64, reason String)
ENGINE = IcebergS3('http://seaweedfs:8333/analytics/sales/returns/', 'tutorialkey', 'tutorialsecret');

INSERT INTO lake.`sales.returns` VALUES (1, 'damaged'), (2, 'wrong size');

SELECT * FROM lake.`sales.returns` ORDER BY id;
```

```response theme={null}
┌─id─┬─reason─────┐
│  1 │ damaged    │
│  2 │ wrong size │
└────┴────────────┘
```

Предложение движка `IcebergS3` задает путь в хранилище для новой таблицы, а `write_full_path_in_iceberg_metadata` указывает ClickHouse зарегистрировать в каталоге полный путь к таблице.

<Note>
  Для создания таблиц через каталог требуется ClickHouse версии 26.8 или выше. Версии с 26.4 по 26.7 записывают файлы таблицы до регистрации пространства имен, что SeaweedFS отклоняет, если пространство имен еще не существует в каталоге; версии до 26.4, по-видимому, выполняются успешно, но файлы таблицы записываются в объектное хранилище без регистрации в каталоге.
</Note>

При коммите вставки ClickHouse каталог SeaweedFS исправляет метаданные, которые экспериментальный writer пока не создает: заполняет отсутствующие ID полей в манифестах, преобразует пути к файлам относительно бакета в абсолютные пути и задает для таблицы сопоставление имен по умолчанию. После этого строгие reader, такие как PyIceberg и Spark, могут читать строки, записанные ClickHouse. Для этого требуется SeaweedFS версии 4.42 или выше.

<div id="loading-data-from-your-data-lake-into-clickhouse">
  ## Загрузка данных из озера данных в ClickHouse
</div>

Чтобы загрузить данные из каталога SeaweedFS в ClickHouse, сначала создайте локальную таблицу ClickHouse:

```sql theme={null}
CREATE TABLE default.orders
(
    `id` Int64,
    `region` String,
    `amount` Float64
)
ENGINE = MergeTree()
ORDER BY (region, id);
```

Затем загрузите данные из таблицы каталога SeaweedFS с помощью `INSERT INTO SELECT`:

```sql theme={null}
INSERT INTO default.orders
SELECT * FROM lake.`sales.orders`;
```
