---
title: 'Абстрактный слой данных'
section: 'Concepts'
weight: 2
description: Абстрактный слой данных, единая модель данных системы, абстракция оборудования и нормализация данных, которые отделяют приложения от физического хранилища.
related:
  - basic-modules/modules
  - data-representation/components
  - architecture/data-collection-layer
  - rest-api
---

Абстрактный слой данных располагается между физическим хранилищем данных и приложениями, которые их используют. Он скрывает физическую реализацию и аппаратные особенности, предоставляя единый интерфейс для работы с данными. Он обеспечивает:

- **Независимость от оборудования**: данные хранятся на разных устройствах (серверах, в облаке, на IoT-устройствах), но приложение взаимодействует с ними через единый интерфейс.
- **Упрощение разработки**: разработчики работают с абстрактными сущностями, не вникая в детали физического хранения.
- **Гибкость**: изменения физической структуры данных (например, переход в облако) не затрагивают приложения.

## Единая модель данных

В системе используется единая модель данных, адаптированная под разные типы оборудования и позволяющая работать с ними единообразно, независимо от их источника или типа оборудования. Она включает общие структуры данных, единые правила обработки и семантическую согласованность данных во всех системах и подсистемах.

Например, единая модель данных системы включает:

- **Сущности**: оборудование, каналы, сеансы, единицы измерения и справочные параметры.
- **Связи**: у оборудования есть каналы, каналы связаны с данными, а данные связаны с сеансами.
- **Атрибуты**: для каждой сущности определены атрибуты (например, `equipment.serial_number` и `channel_data.value`).

### Структура единой модели данных системы

Единая модель данных системы — это структура для хранения и управления данными, связанными с оборудованием, каналами, сеансами и измерениями. Рассмотрим каждую таблицу и её назначение, а также связи между ними.

#### Таблица `channel_data`

В этой таблице хранятся данные, полученные от каналов оборудования в рамках конкретных сеансов.

| Поле              | Тип                              | Описание                                          |
| ----------------- | -------------------------------- | ------------------------------------------------- |
| `id`              | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `equipment_id`    | `bigint`                         | Ссылка на оборудование (`equipment.id`).          |
| `seance_id`       | `bigint`                         | Ссылка на сеанс (`seances.id`).                   |
| `channel_id`      | `bigint`                         | Ссылка на канал (`channels.id`).                  |
| `unit_id`         | `bigint`                         | Ссылка на единицу измерения (`units.id`).         |
| `archive_type_id` | `integer`                        | Ссылка на тип архива (`referenceparameters.id`).  |
| `event_time`      | `integer`                        | Время события (например, временная метка).        |
| `value`           | `character varying(100)`         | Значение, полученное от канала.                   |
| `created_at`      | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`      | `timestamp(6) without time zone` | Время последнего обновления записи.               |

Связи:

- Внешний ключ `unit_id` ссылается на таблицу `units`.
- Внешний ключ `archive_type_id` ссылается на таблицу `referenceparameters`.
- Внешний ключ `equipment_id` ссылается на таблицу `equipment`.
- Внешний ключ `channel_id` ссылается на таблицу `channels`.
- Внешний ключ `seance_id` ссылается на таблицу `seances`.

#### Таблица `units`

В этой таблице хранятся единицы измерения, используемые для данных каналов.

| Поле                | Тип                              | Описание                                          |
| ------------------- | -------------------------------- | ------------------------------------------------- |
| `id`                | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `name`              | `character varying(30)`          | Наименование единицы измерения.                   |
| `varname`           | `character varying(30)`          | Краткое имя переменной для единицы измерения.     |
| `description`       | `character varying(100)`         | Описание единицы измерения.                       |
| `conversion_factor` | `double precision`               | Коэффициент пересчёта для единицы измерения.      |
| `rounding`          | `smallint`                       | Число знаков после запятой для округления.        |
| `synonyms`          | `character varying[]`            | Массив синонимов единицы измерения.               |
| `created_at`        | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`        | `timestamp(6) without time zone` | Время последнего обновления записи.               |

#### Таблица `referenceparameters`

В этой таблице хранятся справочные параметры, такие как типы архивов и прочие квалификаторы.

| Поле                | Тип                              | Описание                                          |
| ------------------- | -------------------------------- | ------------------------------------------------- |
| `id`                | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `name`              | `character varying(30)`          | Наименование единицы измерения.                   |
| `varname`           | `character varying(30)`          | Краткое имя переменной для единицы измерения.     |
| `description`       | `character varying(100)`         | Описание единицы измерения.                       |
| `parent_id`         | `integer`                        | Ссылка на родительский параметр (иерархия).       |
| `referencemodel_id` | `integer`                        | Ссылка на модель справочника.                     |
| `created_at`        | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`        | `timestamp(6) without time zone` | Время последнего обновления записи.               |
| `deleted_at`        | `timestamp(6) without time zone` | Время удаления записи (мягкое удаление).          |

Связи:

- Внешний ключ `parent_id` ссылается на ту же таблицу (`referenceparameters.id`), что позволяет строить иерархии.

#### Таблица `equipment`

| Поле                | Тип                              | Описание                                          |
| ------------------- | -------------------------------- | ------------------------------------------------- |
| `id`                | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `equipment_type_id` | `bigint`                         | Ссылка на тип оборудования.                       |
| `serial_number`     | `character varying(25)`          | Серийный номер оборудования.                      |
| `manufacture_date`  | `timestamp(6) without time zone` | Дата изготовления оборудования.                   |
| `installation_date` | `timestamp(6) without time zone` | Дата установки оборудования.                      |
| `program_version`   | `character varying(100)`         | Версия программного обеспечения оборудования.     |
| `created_at`        | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`        | `timestamp(6) without time zone` | Время последнего обновления записи.               |

#### Таблица `channels`

В этой таблице хранится информация о каналах оборудования.

| Поле                | Тип                              | Описание                                          |
| ------------------- | -------------------------------- | ------------------------------------------------- |
| `id`                | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `equipment_type_id` | `bigint`                         | Ссылка на тип оборудования (`equipment_type.id`). |
| `unit_id`           | `bigint`                         | Ссылка на единицу измерения (`units.id`).         |
| `name`              | `character varying(100)`         | Наименование канала.                              |
| `varname`           | `character varying(20)`          | Краткое имя переменной для канала.                |
| `created_at`        | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`        | `timestamp(6) without time zone` | Время последнего обновления записи.               |

Связи:

- Внешний ключ `equipment_type_id` ссылается на таблицу `equipment_type`.
- Внешний ключ `unit_id` ссылается на таблицу `units`.

#### Таблица `seances`

В этой таблице хранится информация о сеансах связи с оборудованием.

| Поле           | Тип                              | Описание                                          |
| -------------- | -------------------------------- | ------------------------------------------------- |
| `id`           | `bigint`                         | Уникальный идентификатор записи (первичный ключ). |
| `telemetry_id` | `bigint`                         | Ссылка на телеметрию (`telemetry.id`).            |
| `event_time`   | `integer`                        | Время события.                                    |
| `evtid`        | `smallint`                       | Идентификатор события.                            |
| `trycnt`       | `smallint`                       | Количество попыток.                               |
| `tryfl`        | `character varying(12)`          | Флаг попытки.                                     |
| `state`        | `smallint`                       | Состояние сеанса.                                 |
| `btm`          | `integer`                        | Заряд батареи.                                    |
| `rssi`         | `integer`                        | Уровень сигнала (если используется).              |
| `created_at`   | `timestamp(6) without time zone` | Время создания записи.                            |
| `updated_at`   | `timestamp(6) without time zone` | Время последнего обновления записи.               |

#### Общая структура и связи

**Основная таблица** — `channel_data`, которая связывает данные каналов с оборудованием, сеансами и единицами измерения.

**Таблицы-справочники**:

- `units` — единицы измерения.
- `referenceparameters` — типы архивов и прочие квалификаторы.

**Таблицы оборудования**:

- `equipment` — информация об оборудовании.
- `channels` — каналы оборудования.

**Таблица сеансов** — `seances`, в которой хранится информация о сеансах связи.

**Пример использования**:

- Данные каналов (`channel_data`) поступают от оборудования (`equipment`) в рамках конкретных сеансов (`seances`).
- Каждый канал (`channels`) имеет собственную единицу измерения (`units`).
- Тип архива (`referenceparameters`) определяет, как именно следует хранить или обрабатывать данные.

### Преимущества единой модели

Эта модель данных обеспечивает гибкость и масштабируемость для хранения и анализа данных от разного оборудования.

Некоторые преимущества единой модели данных:

- **Согласованность**: данные имеют одинаковую структуру и семантику во всех системах.
- **Масштабируемость**: легко добавлять новые источники данных или типы оборудования.
- **Защита данных**: единые механизмы аутентификации, авторизации и шифрования.
- **Упрощение анализа**: данные можно анализировать едиными инструментами.

## Абстракция оборудования

Абстракция оборудования — это ключевой принцип проектирования системы, который отделяет логику обработки данных от физических характеристик оборудования. Это особенно важно в системах, где используются разнородные устройства.

Абстракция оборудования означает, что система обрабатывает данные на логическом уровне, не зависящем от физических устройств, на которых эти данные хранятся или обрабатываются. Это достигается за счёт:

- **Унификации интерфейсов**: единый способ доступа к данным независимо от оборудования.
- **Сокрытия деталей реализации**: физическое расположение данных, протоколы передачи и прочие технические аспекты скрыты от приложений.
- **Адаптеров**: преобразование данных из формата, специфичного для оборудования, в единый формат.

### Реализация абстракции оборудования

В следующем примере показано, как этот подход реализован в нашей системе. Он прослеживает путь данных от IoT-устройства через адаптер в единую модель данных и наружу через API.

Рассмотрим IoT-устройство, которое передаёт данные о потреблении газа. Реализованные алгоритмы позволяют:

- Получить данные от устройства через адаптер.
- Преобразовать их в структуру `channel_data`.
- Сохранить их в базе данных.
- Предоставить доступ к данным через API.

Для каждого типа оборудования создаются адаптеры, которые обрабатывают специфичные для устройства протоколы и преобразуют данные в единый формат.

**Пример: преобразование данных**

Для IoT-устройства данные могут поступать в формате JSON:

```json title="example.json"
{
  "device_id": "sensor-123",
  "timestamp": 1739950861,
  "value": 42.5
}
```

Адаптер преобразует данные в структуру `channel_data`:

```sql title="example.sql"
INSERT INTO channel_data (equipment_id, seance_id, channel_id,
 archive_type_id, value, event_time)
VALUES (1, 2, 3, 4, '42.5', 1739950861);
```

Запрос данных:

```bash title="Request example"
GET /api/v1/channel_data?equipment_id=1&archive_type=daily&channel_id=3
```

Ответ:

```json title="Response example"
[
  {
    "id": 123,
    "equipment_id": 1,
    "seance_id": 2,
    "channel_id": 3,
    "archive_type_id": 4,
    "value": 42.5,
    "event_time": 1739950861
  }
]
```

### Достоинства абстракции оборудования

- **Независимость от оборудования**: приложения работают с данными, не зная, где те физически находятся.
- **Гибкость**: легко добавлять новые устройства или изменять существующие.
- **Упрощение разработки**: разработчики работают с абстрактными сущностями, не вникая в аппаратные детали.
- **Масштабируемость**: данные могут храниться на разных устройствах, но система продолжает работать единообразно.

## Нормализация данных

Нормализация данных — это процесс организации данных в базе данных таким образом, чтобы минимизировать избыточность и повысить целостность данных. В контексте абстрактного слоя данных нормализация играет ключевую роль в создании единой, эффективной модели данных, пригодной для обработки разных типов оборудования и источников данных.

Нормализация данных разделяет данные на логические таблицы и устанавливает связи между ними, чтобы:

- Исключить дублирование данных.
- Упростить сопровождение и обновление данных.
- Обеспечить целостность данных.
- Повысить производительность запросов.

Единая модель данных системы приведена к (третьей) нормальной форме Бойса — Кодда в части атомарных (скалярных) значений. Некоторые сущности модели данных используют составные структуры для оптимизации обработки редких, нестандартных атрибутов.

### Преимущества нормализации

- **Устранение избыточности**: данные хранятся в одном месте, что снижает избыточность.
- **Согласованность данных**: поддержание согласованности данных упрощается.
- **Гибкость**: легко вносить изменения в структуру данных.
- **Производительность**: повышается производительность запросов (в большинстве случаев).

### Нормализация в контексте абстрактного слоя данных

Нормализация данных — это важный этап проектирования абстрактного слоя данных.

Она позволяет:

- Создать единую модель данных, пригодную для обработки разных типов оборудования.
- Устранить избыточность и дублирование данных.
- Обеспечить целостность и согласованность данных независимо от их источника.
- Упростить интеграцию новых устройств и систем.
