> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Когда использовать тип Map вместо типа JSON для атрибутов в ClickStack

# Типы Map и JSON в ClickStack

export const galaxyOnClick = eventName => () => {
  try {
    if (typeof window !== "undefined" && window.galaxy && eventName) {
      window.galaxy.track(eventName, {
        interaction: "click"
      });
    }
  } catch (e) {}
};

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <Icon />
                <span>Бета</span>
            </a>;
  }
  return <div className="betaBadge">
            <Icon />
            <span>
                Возможность в статусе бета. 
                <u>
                    <a href="/docs/beta-and-experimental-features#beta-features">
                        Подробнее.
                    </a>
                </u>
            </span>
        </div>;
};

[Схема по умолчанию](/ru/clickstack/ingesting-data/schemas) в ClickStack хранит атрибуты ресурсов, областей видимости, логов и спанов в столбцах `Map(LowCardinality(String), String)`. ClickHouse также поддерживает строго типизированный [тип `JSON`](/ru/reference/formats/JSON/JSON), а в ClickStack есть его поддержка в статусе бета в качестве замены `Map`.

**Для типичных рабочих нагрузок обсервабилити мы рекомендуем использовать [схему по умолчанию на основе `Map`](/ru/clickstack/ingesting-data/schemas).** Тип `JSON` доступен пользователям, которые хотят оценить его на рабочих нагрузках с небольшим стабильным набором ключей атрибутов, но для общего применения эта схема не рекомендуется.

<div id="why-map">
  ## Почему Map рекомендуется по умолчанию
</div>

В данных обсервабилити преобладают атрибуты ресурсов, областей видимости, а также атрибуты span и log. Эти наборы обычно велики, имеют высокую мощность и поступают с высокой пропускной способностью. Выбранная для этих атрибутов схема в первую очередь определяет затраты на приём и структуру хранения.

`Map(LowCardinality(String), String)` хранит ключи и значения в единой структуре. Исторически недостаток `Map` заключался в том, что чтение одного ключа требовало чтения всего столбца Map. Теперь это уже не так: ClickHouse поддерживает [сериализацию Map по бакетам](/ru/reference/data-types/map#bucketed-map-serialization), которая разбивает Map на бакеты, так что запросы читают только нужные им бакеты. В сочетании с [текстовыми индексами](/ru/reference/engines/table-engines/mergetree-family/textindexes) по ключам и значениям Map — именно так настроена [схема ClickStack по умолчанию](/ru/clickstack/ingesting-data/schemas) — это делает `Map` избирательным и быстрым при чтении без дополнительных затрат на приём новых ключей.

На практике это означает следующее:

* **Стабильные затраты на приём по мере роста числа ключей.** Добавление нового ключа атрибута не меняет структуру столбцов на диске и не создаёт новые файлы столбцов. Затраты на приём ограничиваются объёмом данных, а не мощностью ключей.
* **Без взрывного роста метаданных.** Количество файлов столбцов на диске не зависит от числа уникальных ключей атрибутов.
* **Избирательные lookup через индексы.** Текстовые индексы по ключам и значениям Map позволяют выполнять точечные lookup без сканирования каждой строки.
* **Предсказуемое поведение при высокой пропускной способности.** Map справляется со всплесками бессхемных наборов атрибутов, которые часто встречаются в трассировке и журналах, без накладных расходов на каждый ключ.

<div id="why-not-json">
  ## Почему не JSON по умолчанию
</div>

Тип `JSON` использует другой подход: при вставке ClickHouse динамически создаёт отдельный строго типизированный подстолбец для каждого обнаруженного пути. При чтении это удобно, поскольку считываются только запрошенные подстолбцы, типы сохраняются и не требуется приведение типов во время выполнения запроса.

Однако компромисс проявляется на этапе приёма. Создание и управление большим количеством динамических подстолбцов увеличивает накладные расходы при записи и усложняет метаданные. Для рабочих нагрузок обсервабилити, где обычно встречаются очень большие или сильно меняющиеся наборы атрибутов и высокая пропускная способность приёма, эти накладные расходы оказываются существенными. Ограничение [`max_dynamic_paths`](/ru/reference/data-types/newjson#reading-json-paths-as-sub-columns) может частично смягчить проблему, помещая дополнительные пути в общий столбец, но доступ к общему столбцу медленнее, чем к выделенным подстолбцам, что снижает преимущество при чтении, ради которого JSON изначально и выбирают.

Поскольку сериализация Map по бакетам устраняет большую часть исторических накладных расходов `Map` при чтении, преимущество `JSON` при чтении для типичных рабочих нагрузок обсервабилити больше не перевешивает его стоимость на этапе приёма.

<div id="when-to-consider-json">
  ## Когда JSON всё ещё стоит рассмотреть
</div>

Тип JSON может быть разумным выбором, если *выполняются все* следующие условия:

* Набор ключей атрибутов **небольшой и стабильный**, то есть у вас не появляются тысячи уникальных ключей, а новые ключи возникают редко.
* Пропускная способность приёма **умеренная** по сравнению с мощностью атрибутов.
* Вам нужен **строго типизированный доступ** к атрибутам без приведения типов на уровне запроса (числа остаются числами, булевы значения — булевыми).
* Вы готовы использовать **бета-возможность** в ClickStack и принимаете, что интеграция может измениться.

Если выполняются не все эти условия, используйте [схему по умолчанию на основе `Map`](/ru/clickstack/ingesting-data/schemas).

<div id="beta-status">
  ## Статус бета
</div>

<Warning>
  **Возможность в статусе бета, не готова к промышленной эксплуатации**

  Поддержка типа JSON в **ClickStack** находится в статусе **бета**. Хотя сам тип JSON готов к промышленной эксплуатации в ClickHouse 25.3+, его интеграция в ClickStack все еще активно разрабатывается и может иметь ограничения, измениться в будущем или содержать ошибки.
</Warning>

В ClickStack поддержка типа JSON в статусе бета доступна с версии `2.0.4`.

<div id="enabling-json-support">
  ## Включение поддержки JSON
</div>

Чтобы использовать схемы с типом JSON вместо [схем на основе `Map`, используемых по умолчанию](/ru/clickstack/ingesting-data/schemas), задайте следующие переменные окружения.

| Переменная                                                      | Где задаётся                   | Назначение                                                                                                            |
| --------------------------------------------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json'` | OTel collector                 | Создаёт схемы в ClickHouse с типом JSON.                                                                              |
| `BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true`                         | HyperDX (интерфейс ClickStack) | Позволяет уровню приложения выполнять запросы к схемам с типом JSON. Только для ClickStack с открытым исходным кодом. |

<div id="managed-clickstack">
  ### Управляемый ClickStack
</div>

Чтобы включить поддержку JSON в Управляемом ClickStack, до настройки коллектора обратитесь в службу поддержки [support@clickhouse.com](mailto:support@clickhouse.com). Эту возможность также нужно включить в интерфейсе ClickStack (HyperDX) в ClickHouse Cloud.

Установите `OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json'` в коллекторе. Например:

```shell theme={null}
docker run -e OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' -e CLICKHOUSE_ENDPOINT=${CLICKHOUSE_ENDPOINT} -e CLICKHOUSE_USER=default -e CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD} -p 8080:8080 -p 4317:4317 -p 4318:4318 clickhouse/clickstack-otel-collector:latest
```

<div id="oss-clickstack">
  ### ClickStack с открытым исходным кодом
</div>

Задайте `OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json'` в любом развертывании, где используется коллектор, и `BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true` на уровне приложения HyperDX, чтобы оно могло выполнять запросы к схемам, использующим тип JSON.

Например:

```shell theme={null}
docker run -e OTEL_AGENT_FEATURE_GATE_ARG='--feature-gates=clickhouse.json' -e OPAMP_SERVER_URL=${OPAMP_SERVER_URL} -e CLICKHOUSE_ENDPOINT=${CLICKHOUSE_ENDPOINT} -e CLICKHOUSE_USER=default -e CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD} -p 8080:8080 -p 4317:4317 -p 4318:4318 clickhouse/clickstack-otel-collector:latest
```

<div id="migrating-from-map-to-json">
  ## Миграция со схемы на основе Map на JSON
</div>

<Warning>
  **Обратная совместимость**

  [тип JSON](/ru/reference/formats/JSON/JSON) **не обратно совместим** с существующими схемами на основе Map. Включение этой возможности создаёт новые таблицы с типом `JSON` и требует ручной миграции данных.
</Warning>

Чтобы перейти со [схем на основе Map по умолчанию](/ru/clickstack/ingesting-data/schemas), выполните следующие шаги:

<Steps>
  <Step>
    ### Остановите OTel коллектор
  </Step>

  <Step>
    ### Переименуйте существующие таблицы и обновите источники данных

    Переименуйте существующие таблицы и обновите источники данных в HyperDX.

    Например:

    ```sql theme={null}
    RENAME TABLE otel_logs TO otel_logs_map;
    RENAME TABLE otel_metrics TO otel_metrics_map;
    ```
  </Step>

  <Step>
    ### Разверните коллектор

    Разверните коллектор, задав `OTEL_AGENT_FEATURE_GATE_ARG`.
  </Step>

  <Step>
    ### Перезапустите контейнер HyperDX с поддержкой схемы JSON

    ```shell theme={null}
    export BETA_CH_OTEL_JSON_SCHEMA_ENABLED=true
    ```
  </Step>

  <Step>
    ### Создайте новые источники данных

    Создайте в HyperDX новые источники данных, указывающие на таблицы JSON.
  </Step>
</Steps>

<div id="migrating-existing-data">
  ### Перенос существующих данных (необязательно)
</div>

Чтобы перенести старые данные в новые JSON-таблицы:

```sql theme={null}
INSERT INTO otel_logs SELECT * FROM otel_logs_map;
INSERT INTO otel_metrics SELECT * FROM otel_metrics_map;
```

<Warning>
  Рекомендуется только для датасетов размером менее \~10 миллиардов строк. Данные, которые ранее хранились в типе Map, не сохраняли точность типов (все значения были строками). В результате в новой схеме эти старые данные будут отображаться как строки, пока не устареют, поэтому на фронтенде потребуется некоторое приведение типов. Для новых данных точность типов будет сохраняться благодаря типу JSON.
</Warning>
