BI Consult Desktop Logo BI Consult Mobile Logo
  • Russian BI Исследование российских bi
  • Перейти на Fine BI
  • Контакты
  • +7 812 334-08-01
    +7 499 608-13-06
  • Отправить сообщение
  • Главная
  • Продукты Эксперт-BI
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Сельское хозяйство
    • Энергетика
    • FMCG
    • Девелоперы
    • Маркетплейсы
    • Пищевая промышленность
    • Фармацевтика
    • Построение Data Platform
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и FP&A
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • IBP
    • ИТ (CIO)
    • Закупки
  • Платформы
    • Системы бизнес-анализа (BI)
    • Интегрированное бизнес-планирование (IBP)
    • Хранилища данных (DWH / Lakehouse)
    • Каталоги данных (Data Catalog)
    • Системы ETL и ELT
    • AI / Исскуственный интеллект
    • Шина данных (ESB)
    • Система управления мастер-данными (MDM)
    • Семантический слой
  • Услуги
    • Переход на отечественные BI и DWH системы
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений и DWH
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Курсы
    • Учебный курс Информационная грамотность (Data Literacy)
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Greenplum
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt (Data Build Tool)
  • Компания
    • Руководство
    • Новости
    • Клиенты
    • Карьера
    • Скачать
    • Контакты

BI

  • FineBI
  • FineReport
  • FineDataLink
  • FineChatBI (FineAI)
  • Коннекторы данных из 1С в BI
  • Airflow / Nifi
  • Visiology
  • PIX BI
  • Modus BI
  • Yandex.DataLens
  • Open-source BI: Superset/Metabase
  • Luxms BI
  • AW BI + Alpha BI
  • FlyBI + Форсайт. Аналитическая Платформа
  • Loginom
  • Триафлай
  • AI / Исскуственный интеллект
  • Optimacros
  • Навигатор BI
  • Семантический слой

СУБД

  • Arenadata
  • ClickHouse
  • Greenplum
  • Postgres Professional
  • TData

Другое

  • Построение Data Platform
    • Аналитическое хранилище данных
    • Data Lake и Data Engineering
    • Подробнее про Data Lake
    • Внедрение Lakehouse
      • Apache Doris
      • StarRocks
      • Trino
    • Миграция витрин из пропиетарных DWH на новый стек
    • Учебный курс "Современная архитектура хранилища данных"
Главная » Курсы по системам бизнес-анализа и методологии » Учебный курс по ClickHouse » Энциклопедия ClickHouse » clickhouse tree

clickhouse tree

 

Краткое введение

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

 

Введение

ClickHouse как колоночная СУБД для аналитики изначально ориентирован на скоростные агрегации и сквозную обработку больших массивов данных. Работа с деревовидными структурами в таком контексте требует особого подхода: мы не просто храним дерево как набор записей, а создаём витрину данных, которая позволяет быстро находить потомков, предков, поддеревья и агрегировать значения на разных уровнях. В этой главе мы рассмотрим, как моделировать дерево в ClickHouse, какие архитектурные паттерны применяются на практике, какие алгоритмы дают баланс между производительностью и простотой поддержки, а также как интегрировать решения с существующими процессами загрузки данных и операциями обновления дерева.

Мы будем обсуждать три базовых паттерна моделирования дерева в ClickHouse:

  • материализованный путь (materialized path) и различные форматы пути;
  • иерархический список (adjacency list) и его варианты;
  • вложенные множества (nested sets) и прямая работа с диапазонами.
    Плюсы и минусы каждого подхода будут иллюстрированы примерами реальных задач и конкретными SQL‑конструкциями.

Кроме того, в главе приведены примеры open-source и российских продуктов, которые помогают реализовать или интегрировать концепцию clickhouse tree в реальные решения.

 

Теоретические основы и терминология

Понимание дерева в контексте ClickHouse требует знакомства с основными моделями представления иерархии:

  • Узел (node): элемент дерева, чаще всего представляет запись в таблице с уникальным идентификатором.
  • Родительский узел (parent): ссылка на родителя узла, если таковой существует.
  • Потомок (descendant) / предок (ancestor): узлы, находящиеся в поддереве или над деревом относительно данного узла.
  • Уровень глубины (depth): расстояние от корня до данного узла; корень имеет depth = 0.
  • Путь (path): последовательность идентификаторов, выражающая местоположение узла в дереве. Форматы путей различаются: строковый путь, массив идентификаторов, числовой диапазон и т. д.
  • Вложенные множества (nested sets): подход, где у узлов есть границы left и right, позволяющие определить поддерево по диапазону.
  • Материализованный путь (materialized path): хранение пути узла как последовательности идентификаторов; позволяет быстро находить поддеревья через LIKE/паттерны или функции массивов.
  • Аджасент-лист (adjacency list): классическая модель, где каждая запись содержит ссылку на родителя; простая вставка, но сложная навигация вниз по дереву без рекурсии.
  • Closure table: таблица смежности, содержащая все пары (ancestor, descendant) для ускорения запросов на поддеревья, но требующая поддержания при модификации дерева.
  • Рекурсивные запросы: концепция чрез поиск по дереву через повторяющиеся вычисления; в ClickHouse поддержка ограничена и зависит от версии и методики реализации.

Правильный выбор модели зависит от реальных сценариев:

  • частота обновлений дерева;
  • размер поддеревьев и глубины;
  • требования к чтению поддеревьев и агрегирования по уровням;
  • ограничения на хранение и сложность поддержки.

Совокупность паттернов и техник позволяет строить гибкую и быстро масштабируемую архитектуру деревьев под аналитические нагрузки.

 

Методологии и подходы

 

Выбор паттерна моделирования

  • Материализованный путь: предпочтителен, когда требуется частый доступ к поддеревьям и скорости чтения. Проблема - обновления пути при перемещении узлов.
  • Аджасент-лист: прост в реализации и поддержке вставок, но не даёт эффективных поддеревьев без рекурсивных операций.
  • Вложенные множества: обеспечивает очень быстрый доступ к поддеревьям по диапазонам, но требует сложных обновлений и поддержки целостности диапазонов.
  • Closure-таблица: обеспечивает очень быстрые чтения поддеревьев, но требует поддержки синхронного обновления множества пар ancestor-descendant.

     

Выбор подхода под конкретные сценарии

  • Данные с редкими изменениями, но частыми запросами поддеревьев: материализованный путь или вложенные множества.
  • Динамическая иерархия с частыми перемещениями узлов: adjacency list в сочетании с паттернами обновления, либо closure-таблицы.
  • Необходимость аналитики по всей иерархии и частые агрегации на разных уровнях: гибридные схемы, сочетающие PAT для предков и агрегированные показатели в уровне.

     

Архитектурные принципы

  • Логика владения данными: держать деревья рядом с фактическими фактами, к которым они относятся (например, товары в каталоге).
  • Нормализация vs денормализация: денормализация путей для быстрого чтения, нормализация для экономии обновлений.
  • Экономика обновлений: в ClickHouse обновления обычно реализуются через UPDATE/ALTER UPDATE; планируйте пакетные обновления вместо частых мелких изменений.
  • Вопросы консистентности: при использовании materialized path требуется аккуратная логика перемещений узлов; closure-таблица - дополнительная таблица для поддержания целостности.

     

Архитектура и технологическая реализация

 

Архитектурный паттерн 1. Материализованный путь (Materialized Path)

  • Модель данных:

    • id UInt64
    • parent_id UInt64
    • name String
    • path String - путь вида "/1/42/377/"
    • depth UInt8
    • attributes Nested('key String','value String') или JSONString
  • Пример DDL:

    
    CREATE TABLE tree_materialized_path
    (
      id UInt64,
      parent_id UInt64,
      name String,
      path String,
      depth UInt8,
      metadata String
    )
    ENGINE = MergeTree()
    ORDER BY (path);
    
  • Пример загрузки узла:

    
    INSERT INTO tree_materialized_path (id, parent_id, name, path, depth, metadata)
    VALUES (1, 0, 'Корень', '/1/', 0, '{}');
    
  • Как выполнять запросы поддеревьев:

    
    -- все узлы под корнем
    SELECT *
    FROM tree_materialized_path
    WHERE path LIKE '/1/%'
    ORDER BY depth, path;
    
  • Условия обновления при перемещении узла:

    
    -- переместить узел 3 под узел 4
    -- шаги:
    -- 1) обновить path для узла 3 и его поддерева;
    -- 2) обновить depth;
    -- 3) при необходимости обновить дочерние пути с новыми префиксами.
    
  • Преимущества:

    • простота чтения поддеревьев;
    • быстрые агрегаты по уровням через depth.
  • Риски:

    • дорогостоящие обновления путей на больших деревьях;
    • неэффективное хранение огромных путей в строковом формате.

       

Архитектурный паттерн 2. Аджасент-лист (Adjacency List)

  • Модель данных:

    • id UInt64
    • parent_id UInt64
    • name String
    • depth UInt8
    • attributes String
  • Пример схемы:

    
    CREATE TABLE tree_adjacency
    (
      id UInt64,
      parent_id UInt64,
      name String,
      depth UInt8,
      attributes String
    )
    ENGINE = MergeTree()
    ORDER BY (id);
    
  • Вызовы без рекурсивных функций:

    • Для поддеревьев можно использовать iterative подходы в приложении или заранее построенные closure-таблицы.
  • Преимущества:

    • простота обновлений;
    • компактность хранения.
  • Риски:

    • запрос поддерева требует обхода большого количества узлов, что неэффективно без помощи дополнительных структур.

       

Архитектурный паттерн 3. Вложенные множества (Nested Sets)

  • Модель данных:

    • node_id UInt64
    • left UInt64
    • right UInt64
    • name String
  • Пример структуры:

    
    CREATE TABLE tree_nested
    (
      node_id UInt64,
      lft UInt64,
      rgt UInt64,
      name String
    )
    ENGINE = MergeTree()
    ORDER BY (lft, rgt);
    
  • Выбор поддеревья по диапазону:

    
    SELECT *
    ## FROM tree_nested
    WHERE lft >= :node_left AND rgt 
  • Преимущества:

    • очень быстрые поддеревья и вычисление размера поддерева;
    • простая агрегация по глубине.
  • Риски:

    • обновление дерева влечёт широкомасштабные модификации значений lft/rgt;
    • поддержка целостности требует дисциплины и дополнительных инструментов.

       

Архитектура гибридов и интеграции

На практике часто применяются гибридные решения:

  • хранение основных узлов в Materialized Path, а closure-таблицы для ускорения сложных запросов;
  • использование Kafka Engine для стримого ввода в дерево, последующая агрегация в ClickHouse;
  • соединение с внешними системами для управления иерархиями (например, ERP/CRM-системы) через ETL-пайплайны.

     

Организационные и процессные аспекты

  • Управление данными дерева:

    • определение ответственных лиц за модель дерева;
    • политика обновлений узлов: кто может менять родительство, как фиксируются перемещения, какие транзакционные ограничения действуют.
  • Контроль качества данных:

    • валидация целостности шляхов и диапазонов;
    • контроль дубликатов узлов;
    • мониторинг производительности чтения поддеревьев.
  • Процессы обновления:

    • пакетная обработка изменений (batch updates) с использованием ALTER UPDATE (для MergeTree) и терминаловой обработки в ETL;
    • планирование миграций между моделями (например, из adjacency list к materialized path).
  • Архитектура эксплуатации:

    • выделение отдельных таблиц для дерева и фактов, чтобы не мешать нагрузке;
    • использование TTL и partitioning для балансировки по времени и глубине.

       

Технические детали реализации (алгоритмы, схемы, протоколы, интеграции)

 

Алгоритм обновления пути при перемещении узла в Materialized Path

  1. Найти узел-источник и целевого родителя.
  2. Вычислить новый путь: новый_path = concat(parent_path, '/', id, '/').
  3. Обновить путь для узла и всех его потомков:
    • собрать идентификаторы узлов в поддереве через обновление шаблона пути.
    • применить пакетное обновление на поддереве, чтобы минимизировать коллизии.

Пример псевдоSQL-подхода (упрощённый):


-- шаг 1: определить новый путь
SELECT path FROM tree_materialized_path WHERE id = :node_id;
SELECT path FROM tree_materialized_path WHERE id = :new_parent_id;

-- шаг 2: обновить поддерево
-- обновление для узла и всех потомков предполагается в рамках транзакции или пакетами
ALTER UPDATE path = concat(:new_parent_path, '/', toString(id), '/')
WHERE path LIKE concat('%/', :node_id, '/%');

Иерархическая аналитика с использованием массивов

  • В некоторых случаях полезно хранить массив идентификаторов по каждому узлу:

    
    ALTER TABLE tree_materialized_path ADD COLUMN path_arr Array(UInt64);
    
  • Поиск поддерева по массиву:

    
    SELECT *
    FROM tree_materialized_path
    WHERE has(path_arr, :ancestor_id);
    
  • Преимущества:

    • гибкость в фильтрациях;
    • возможность агрегаций по уровням с использованием массивов.
  • Риски:

    • увеличение размера записей;
    • сложность поддержания корректности path_arr при перемещениях.

       

Интеграции с внешними системами

  • Интеграции через коннекторы:
    • Kafka для потоковой загрузки дерева в ClickHouse;
    • DataLens или другие BI-инструменты (например, Yaндекс DataLens) для визуализации деревьев и обзоров по уровням.
  • Взаимодействие с российскими решениями:
    • Яндекс YDB как база для поддержания внешних иерархий, синхронизируемых с ClickHouse для аналитики;
    • Яндекс DataLens для визуализации деревьев и анализа по поддеревьям;
    • использование сервисов СберКлауда (SberCloud) или Яндекс Облако для размещения ETL-процессов и загрузки данных.

       

Риски, ограничения и типовые ошибки

  • Производительность обновлений дерева:
    • частые перемещения узлов в Materialized Path требуют дорогостоящих обновлений; планируйте пакетные операции.
  • Размер путей и памяти:
    • длинные строковые пути могут приводить к увеличению памяти и индексации; стоит рассмотреть альтернативы (path_arr, left-right диапазоны).
  • Каркас поддеревьев:
    • для больших деревьев adjancency list без дополнительных структур может привести к медленным запросам по поддеревьям; не обходиться без вспомогательных таблиц или кэширования.
  • Целостность данных:
    • поддержка целостности в гибридных решениях требует механизмов контроля изменений, журналирования и CI/CD-процедур.
  • Взаимодействие с обновлениями в потоках:
    • обработка изменений в реальном времени требует зрелых пайплайнов и синхронизации между источниками.

       

Типовые ошибки:

  • смешение форматов путей и неконсistentность в глубине;
  • пренебрежение тестированием на больших деревьях;
  • игнорирование индексации по пути или диапазонам, что приводит к O(n) сканированиям вместо O(log n) или O(k).

     

Заключение

Работа с деревьями в ClickHouse - это сочетание подходов к моделированию, продуманной архитектуры чтения и продуманной обработки изменений. Выбор конкретного паттерна зависит от нагрузки, частоты изменений и требований к аналитике. Материализованный путь обеспечивает быстрые чтения поддеревьев; вложенные множества - эффективны для целостной фильтрации по диапазонам; аджасент-лист хорошо подходит для динамичных структур, если дополняется механизмами ускорения. Гибридные решения, которые сочетают несколько паттернов, позволяют балансировать между скоростью чтения, стоимостью обновлений и простотой эксплуатации.

В рамках курса "Clickhouse" навык проектирования деревьев в ClickHouse становится основой для построения качественных аналитических платформ: от каталогов и иерархий в бизнес-доменной области до сложной оценки влияния поддеревьев на ключевые бизнес‑показатели. Важно помнить, что эффективная архитектура дерева не ограничивается одной таблицей - это набор структур, процессов загрузки и обновления, стратегий доступа и интеграций с внешними системами, реализованных в рамках единого технологического стека.

 

FAQ

  1. Что такое clickhouse tree в контексте аналитической архитектуры?
  • Это концептуальное обозначение хранения и обработки древовидных структур в ClickHouse: методы моделирования (materialized path, adjacency list, nested sets), а также подходы к обновлениям, агрегациям и интеграции с источниками данных.

 

  1. Когда предпочтительнее использовать материализованный путь?
  • Когда основная потребность - быстрая навигация по поддеревьям и агрегации по уровням; однако следует заранее продумать паттерн обновления путей при перемещении узлов.

 

  1. Как обеспечить быстрый доступ к поддеревьям в ClickHouse?
  • Через паттерны: materialized path с индексами по пути, либо вложенные множества (left/right) с диапазонами; в некоторых случаях - closure-таблицы.

 

  1. Какие инструменты и российские решения помогают работать с деревьями?
  • Российские продукты: Яндекс YDB как источник структуры для поддержки внешних деревьев; Яндекс DataLens для визуализации и анализа; интеграция ClickHouse с Яндекс DataLens и облачными решениями (Яндекс Облако, СберCloud) для ETL и аналитики.

 

  1. Какой риск связан с обновлениями в деревьях?
  • Основной риск - стоимость обновления путей/диапазонов на больших поддеревьях; следует накладывать пакетные обновления и предусмотреть трафик на периодических переформированиях.

 

  1. Возможно ли смешивать паттерны для сложных деревьев?
  • Да. Гибридные архитектуры часто дают лучший компромисс между обновлениями, чтением и масштабированием: материализованный путь для чтения поддеревьев и closure-таблица для быстрого доступа к соединениям между узлами.

 

  1. Как тестировать производительность запросов к деревьям?
  • Тесты на выборке поддеревьев с разной глубиной и размером, benchmarks с реальными сценариями, профилирование запросов через системные таблицы ClickHouse, мониторинг по времени выполнения и вовлеченных узлах.

 

  1. Какие сетевые и инфраструктурные требования?
  • Надежное хранение путей и индексов, настройка партиционирования по времени и глубине, потоковые источники (Kafka) для загрузки изменений, резервирование и мониторинг.

 

  1. Какие практики DevOps полезны для деревьев?
  • Контроль версий схемы дерева, миграции между паттернами, тестирование изменений на staging, согласование между ETL-командами и аналитиками, автоматизация обновлений узлов.

 

  1. Какие будущие направления стоит рассмотреть?
  • Улучшение поддержки рекурсивных запросов в ClickHouse, расширение возможностей кросс-соединений между деревьями в разных источниках данных, добавление автоматизированного кэширования поддеревьев, а также усиление инструментов визуализации для больших иерархий.

 

← Предыдущая статья
clickhouse concat
Следующая статья →
ClickHouse: Архитектура, принципы и реализация

 

Узнать стоимость решенияЗапросить видео презентацию

Решения

Анализировать ФинансыУвеличивайте ПродажиОптимальный Склад и ЛогистикаМаркетинговые Метрики

Клиенты
  • ООО «Модум-Транс» — независимый оператор грузовых железнодорожных перевозок, лидирующий по количеству инновационного парка на сети РЖД.

  • Novikov group – первый российский ресторанный холдинг, основанный в 1991 году. Это команда профессионалов под управлением Аркадия Новикова, реализующая широкий спектр услуг в сфере гостеприимства: от проведения event-мероприятия до управления рестораном, от установления стандартов сервиса до контроля качества готовой продукции, от построения бизнес-плана проекта до реализации франшизы.

  • MoneyCare — кредитная платформа и сервис для ПОС-кредитования в магазинах, установленная в более чем 18 тысячах трейдинговых точек и сотрудничающая с 11 главными банками России.

  • НПФ «Будущее» — один из крупнейших негосударственных пенсионных фондов России, предоставляющий услуги по пенсионному обеспечению и накоплениям. Фонд активно внедряет цифровые технологии для повышения качества обслуживания клиентов.

  • Решения
    • Дистрибуция
    • Розничная торговля
    • Производство
    • Операторы связи
    • Страхование
    • Банки
    • Лизинг
    • Логистика
    • Нефтегазовый сектор
    • Медицина
    • Сеть ресторанов
    • E-Commerce
    • Энергетика
    • Фармацевтика
  • Услуги
    • Переход на отечественные BI и DWH
    • Консалтинг
    • Пилотный проект
    • Обучение и сертификация
    • Бесплатное обучение
    • Техническая поддержка
    • Технические задания
    • Сбор требований для проекта внедрения BI-системы
    • CI/CD для DWH
    • Аудит BI приложений
    • Выделенная команда
    • Настойка и поддержка баз данных
    • Разработка BI Стратегии
    • Styleguide для BI-системы
    • Как выбрать BI-систему
  • Платформы
    • FineBI
    • FineReport
    • FineDataLink
    • Коннекторы данных из 1С в BI
    • Airflow + NiFi
    • Visiology
    • Luxms BI
    • Modus BI
    • PIX BI
    • Arenadata
    • ClickHouse
    • Greenplum
    • Postgres Professional
    • Open-source BI: Superset/Metabase
    • Loginom
    • Yandex.DataLens
    • AI / Исскуственный интеллект
    • Optimacros
    • Шины данных
  • Курсы
    • Учебный курс Информационная грамотность
    • Учебный курс для бизнес-аналитиков
    • Учебный курс для системных аналитиков
    • Учебный курс по Data Governance
    • Учебный курс Как стать CDO
    • Учебный курс Современная архитектура хранилища данных
    • Учебный курс по Fine BI
    • Учебный курс по FineReport
    • Учебный курс по DWH
    • Учебный курс по Data Science (ML, AI)
    • Учебный курс по PostgreSQL
    • Учебный курс по Apache Airflow и NiFi
    • Учебный курс по Open-source BI
    • Учебный курс по ClickHouse
    • Учебный курс по DataLens
    • Учебный курс по Loginom
    • Учебный курс по Modus BI и ETL
    • Учебный курс по Visiology
    • Учебный курс по dbt
  • Функциональные решения
    • Создание Data Lake
    • Цифровая трансформация
    • Управление по KPI
    • Финансы
    • Продажи
    • Склад
    • HR
    • Маркетинг
    • Внутренний аудит
    • Категорийный менеджмент
    • S&OP и прогнозная аналитика
    • Геоаналитика
    • Цепочки поставок (SCM)
    • AutoML
    • Process Mining
    • Сквозная аналитика
  • Компания
    • О нас
    • Руководство
    • Новости
    • Клиенты
    • Скачать
    • Контакты
    • Политика конфиденциальности
RutubeVkontakteLinkedInYouTube
ООО "Би Ай Консалт",
ИНН: 7811437757,
ОГРН: 1097847154184
199178, Россия,
Санкт-Петербург,
6-ая линия В.О., Д. 63, 4 этаж
Тел: +7 (812) 334-08-01
Тел: +7 (499) 608-13-06
E-mail: info@biconsult.ru

 

 

 

 

 

×

Пользуясь сайтом, вы соглашаетесь с использованием cookies и политикой конфиденциальности.