Привет, Хабр!

Всем хорош Data Vault, однако схватиться с ним «врукопашную», используя только SQL, захочет не каждый. Останавливает большой объем ручных операций, а также большой объем деталей реализации. Большое количество join, за которые критикуют Data Vault, не является определяющим моментом, так как уже сейчас базы данных способны их эффективно обрабатывать, а с течением времени мощность серверов только возрастает.

Но творческая мысль не дремлет, постепенно появляются инструменты для автоматизации построения Data Vault. Например, это пакет AutomateDV для dbt, графическая надстройка над ним Datapulse, построение модели DV в BI.Qube.

Data Vault меня заинтересовал — уж много плюшек он сулит, и для его изучения я занимаюсь проектом asapBI — low‑code IDE для моделирования DWH. Требования к создаваемой системе я описал на сайте asapbi.ru. Их достаточно много, поэтому не буду их тут перечислять.

Сегодня я хотел поделиться графическим интерфейсом для создания хабов, линков и стеллитов. Критика приветствуется и очень желательна:‑)

Внешний вид IDE asapBI

asapBI реализован как плагин к VSCode или Theia:

Рис. 1. Внешний вид IDE asapBI
Рис. 1. Внешний вид IDE asapBI

Слева - дерево с базами данных (NORD, ASGARD, ...), схемами (repo_md, repo_fi), каталогами (ODS, DDS...), таблицами (sales_raw) и хабами (new_hub77, sales_hub...). За работу с базами отвечает модуль генерации SQL - для каждой базы он свой. Пока поддерживается только Greenplum.

Задача: создать в схеме FI новую папку, в ней 2 хаба с сателлитами, а затем связать хабы с помощью линка. Диаграмма будет выглядеть так:

Рис. 2. Модель данных
Рис. 2. Модель данных

1. Создание папки

При наведении мыши на схему или существующую папку можно создать новую:

Рис. 3. Создание папки - ввод наименования
Рис. 3. Создание папки - ввод наименования

Система при создании спрашивает, в какой пакет этот объект записать. Пакет потом поедет по ландшафту в тест, и далее в прод. Но мы не собираемся переносить этот объект, поэтому оставляем как есть:

Рис. 4. Объект временный, по ландшафту не переносим
Рис. 4. Объект временный, по ландшафту не переносим

Папка создана, можно закрывать мастер:

Рис. 5. Папка создана
Рис. 5. Папка создана

2. Создание хабов

Аналогично создаем первый хаб - Продукт

Рис. 6. Создание хаба - выбор типа объекта Hub
Рис. 6. Создание хаба - выбор типа объекта Hub

На второй страничке мастера ничего не меняем — хаб временный:

Рис. 7. Хаб временный, по ландшафту не переносим
Рис. 7. Хаб временный, по ландшафту не переносим

После сохранения хаб появляется в дереве объектов.

Рис. 8. Хаб создан успешно
Рис. 8. Хаб создан успешно

Нажатие на кнопку "Open object" закрывает мастер и открывает хаб на редактирование.

Выполненный при создании хаба DDL-запрос имеет следующий вид (комментарии к колонкам удалены, чтобы не замыливать):

CREATE TABLE repo_fi.product_demo_hub (
	date_load date DEFAULT now() NOT NULL, -- Дата загрузки
	src_sys text DEFAULT ''::character varying NOT NULL, -- Система - источник
	hkey int8 GENERATED BY DEFAULT AS IDENTITY
               ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 
                 START 1 CACHE 20 NO CYCLE) NOT NULL, -- Ключ хаба
	CONSTRAINT product_demo_hub_pkey PRIMARY KEY (hkey)
)
USING heap
DISTRIBUTED REPLICATED;
COMMENT ON TABLE repo_fi.product_demo_hub IS '{ "app": "asapBI",
"descr": "Product Demo hub",
"type": "HUB",
"folder": "161"
}';

Ничего не мешает вручную, например, в DBeaver, выполнить этот код, и хаб точно так же появится в дереве объектов

Для просмотра всех полей удобно поставить чекбокс «Показывать служебные поля». По умолчанию они скрыты, чтобы не размывать фокус внимания.

Рис. 9. Редактирование хаба
Рис. 9. Редактирование хаба

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

Рис. 10. Кнопки редактирования хаба
Рис. 10. Кнопки редактирования хаба

Кнопки по порядку:

  1. Создание поля (бизнес-ключа);

  2. Создание сателлита;

  3. Создание линка.

Используя первые две кнопки «Создание поля» и «Создание сателлита», формируем хаб «Продукт» и сателлит:

Рис. 11. Готовый хаб и сателлит
Рис. 11. Готовый хаб и сателлит

При сохранении хаба и сателлита формируется следующий DDL-код:

ALTER TABLE repo_fi.product_demo_hub DROP CONSTRAINT product_demo_hub_unique; 
ALTER TABLE repo_fi.product_demo_hub ADD product text; 
COMMENT ON COLUMN repo_fi.product_demo_hub.product IS 'Продукт';
ALTER TABLE repo_fi.product_demo_hub ADD CONSTRAINT 
   product_demo_hub_unique UNIQUE ( product );

CREATE TABLE repo_fi.product_demo_hub_sat1 (
   id bigint GENERATED BY DEFAULT AS IDENTITY primary key,
   hkey bigint NOT NULL,
   valid_from date DEFAULT now() NOT NULL,
   date_load date DEFAULT now() NOT NULL,
   src_sys text DEFAULT ''::character varying NOT NULL,
   brand text,  --Брэнд
   categ text,  --Категория продукта
   FOREIGN KEY (hkey) REFERENCES repo_fi.product_demo_hub (hkey)
)
USING heap
DISTRIBUTED REPLICATED;
COMMENT ON TABLE repo_fi.product_demo_hub_sat1 IS '{ "app": "asapBI",
"descr": "New sat",
"type": "SAT",
"owner": "repo_fi.product_demo_hub"
}';

ALTER TABLE repo_fi.product_demo_hub_sat1 ADD CONSTRAINT 
    product_demo_hub_sat1_unique UNIQUE (hkey, valid_from);

Тру олд-скул программисты могут выполнить этот SQL напрямую в базе данных и результат будет тем же самым - в дереве появится хаб и сателлит.

Аналогично создаем новый хаб "Покупатель", на это раз без сателлита, но с линком:

Рис. 12. Готов второй хаб - Покупатель
Рис. 12. Готов второй хаб - Покупатель

При необходимости к линку можно добавить сателлиты (выделенная кнопка +Sat).

DDL при создании хаба:

CREATE TABLE repo_fi.customer_demo_hub (
	date_load date DEFAULT now() NOT NULL, -- Дата загрузки
	src_sys text DEFAULT ''::character varying NOT NULL, -- Система - источник
	hkey int8 GENERATED BY DEFAULT AS IDENTITY
               ( INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 
                 START 1 CACHE 20 NO CYCLE) NOT NULL, -- Ключ хаба
	customer text NULL, -- Покупатель
	CONSTRAINT customer_demo_hub_pkey PRIMARY KEY (hkey),
	CONSTRAINT customer_demo_hub_unique UNIQUE (customer)
)
USING heap
DISTRIBUTED REPLICATED;
COMMENT ON TABLE repo_fi.customer_demo_hub IS '{ "app": "asapBI",
"descr": "Customer Demo hub",
"type": "HUB",
"folder": "161"
}';

Добавление к хабу поля и линка генерирует такой DDL:

ALTER TABLE repo_fi.customer_demo_hub DROP CONSTRAINT customer_demo_hub_unique; 
ALTER TABLE repo_fi.customer_demo_hub ADD customer text; 
COMMENT ON COLUMN repo_fi.customer_demo_hub.customer IS 'Покупатель';
ALTER TABLE repo_fi.customer_demo_hub 
    ADD CONSTRAINT customer_demo_hub_unique 
    UNIQUE ( customer );

CREATE TABLE repo_fi.customer_demo_hub_link1 (
   id bigint GENERATED BY DEFAULT AS IDENTITY primary key,
   customer_demo_hub bigint,
   date_load date DEFAULT now() NOT NULL,
   src_sys text DEFAULT ''::character varying NOT NULL,
   product_demo_hub bigint ,
   FOREIGN KEY (customer_demo_hub) REFERENCES repo_fi.customer_demo_hub (hkey),
   FOREIGN KEY (product_demo_hub) REFERENCES repo_fi.product_demo_hub (hkey)
)
USING heap
DISTRIBUTED REPLICATED;
COMMENT ON TABLE repo_fi.customer_demo_hub_link1 IS '{ "app": "asapBI",
"descr": "New link",
"type": "LINK"
}';

ALTER TABLE repo_fi.customer_demo_hub_link1
    ADD CONSTRAINT customer_demo_hub_link1_unique 
    UNIQUE (customer_demo_hub, product_demo_hub);

Результат в папке DEMO:

  • два хаба, один с сателлитом

  • один линк на оба хаба, представлен в дереве ниже как под первым хабом, так и под вторым.

Рис. 13. Результат моделирования
Рис. 13. Результат моделирования

Что дальше?

А дальше — загружаем данные в созданную модель, но это уже тема другой публикации...

Комментарии (0)