Silver¶
В данном разделе приведены сведения о Silver, плагине для СУБД Picodata.
Picodata Enterprise
Функциональность плагина доступна только в коммерческой версии Picodata.
Общие сведения¶
Плагин Silver используется для расчёта себестоимости при работе с Picodata.
Состав плагина¶
Внутри архива с плагином находится структура вложенных директорий, включающая имя и версию плагина, а также его файлы:
└── silver
└── 0.7.0
├── libsilver.so
├── manifest.yaml
├── migrations
│ ├── 0001_tables.db
│ ├── 0002_results_sum_type.db
│ ├── 0003_calc_settings.db
│ ├── 0004_use_uuids.db
│ ├── 0005_compound_attributes.db
│ └── 0006_new_model.db
└── silver-cli
Основная логика плагина обеспечивается разделяемой библиотекой
libsilver.so. Исходная конфигурация плагина задается в файле манифеста
(manifest.yaml). В директории migrations находятся миграции плагина:
они создают/удаляют тестовые таблицы для проведения вычислений расчёта
стоимости при включении/отключении плагина
соответственно. Исполняемый файл silver-cli используется для
выполнения операций в плагине: загрузки данных, запуска расчёта, очистки
таблиц с промежуточными результатами (при необходимости).
Подключение плагина¶
Содержимое архива с плагином следует распаковать в любую удобную
директорию, которую после этого нужно будет указать как SHARE_DIR для
инстанса Picodata.
При запуске одного инстанса из командной строки директорию плагина можно указать с помощью параметра:
picodata run --share-dir=<SHARE-DIR> ...
Однако, для полноценной использования плагина рекомендуется запустить кластер с помощью роли Ansible.
После запуска Picodata с поддержкой плагинов в заданной директории подключитесь к административной консоли инстанса Picodata.
Установите плагин, добавьте его к тиру, запустите миграции и включите его с помощью следующих SQL-команд:
CREATE PLUGIN silver 0.7.0;
ALTER PLUGIN silver 0.7.0 ADD SERVICE silver TO TIER default;
ALTER PLUGIN silver MIGRATE TO 0.7.0;
ALTER PLUGIN silver 0.7.0 ENABLE;
Для диагностики работы плагина обратитесь к отладочному журналу инстанса Picodata.
Конфигурация плагина¶
Исходная конфигурация плагина задается в файле manifest.yaml:
description: Plugin Silver - costs allocation
name: silver
version: 0.7.0
services:
- name: silver
description: Costs allocation
default_configuration:
calc_model: allocation
clear_intermediate: true
complete_batch_size: 50
complete_pool_size: 100
difference_limit: 50
iterations_limit: 150
max_step: 150
results_allocation_only: false
results_batch_size: 20000
step_batch_size: 50
step_pool_size: 2000
decimal_points: 2
migration:
- migrations/0001_tables.db
- migrations/0002_results_sum_type.db
- migrations/0003_calc_settings.db
- migrations/0004_use_uuids.db
- migrations/0005_compound_attributes.db
- migrations/0006_new_model.db
Для изменения доступны следующие параметры в блоке default_configuration:
calc_model— модель расчёта (allocationилиfinal_receivers, см. ниже)clear_intermediate— признак удаления промежуточных результатовcomplete_batch_size— размер пакета для записи окончательных результатов расчётаcomplete_pool_size— количество вершин (узлов расчёта), одновременно сохраняющих окончательные результатыdifference_limit— размер общей допустимой погрешности. Если сумма входящих затрат во всех вершинах в начале очередного шага будет меньше значения этого параметра, расчёт завершитсяiterations_limit— ограничение на число записей, которые обработает отдельный узел расчёта перед тем, как отдать управление другому узлуmax_step— максимально число итераций расчётаnode_difference_limit— аналогичноdifference_limit, но для отдельной вершины (узла расчёта)results_allocation_only— сохранять в результате только распределённые затраты, без учёта плановых сумм (базы распределения)step_batch_size— размер пакета для записи промежуточных результатовstep_pool_size— количество вершин (узлов расчёта), выполняющих расчёт одновременно
Управление действиями плагина¶
Для выполнения некоторых операций в плагине используйте консольное
приложение silver-cli, входящее в состав поставки плагина. Приложение
позволяет загрузить данные в таблицы плагина отдельными порциями
(пакетами), запустить расчёты, а также выполнять дополнительные
действия. Полный список функций приведён ниже:
Использование: silver-cli [ПАРАМЕТРЫ] [КОМАНДЫ]
Команды:
version Выводит версию на экран
import-data Загружает данные в Picodata для расчёта себестоимости
run-calc Запускает расчёт
drop-intermediate Удаляет таблицы с промежуточными результатами
change-sign Меняет знак суммы в файле базы распределения на противоположный и сохраняет результат в указанный файл
export-result Выгружает данные указанного расчёта в формате CSV в заданную директорию
Параметры:
--host <HOST> Адрес инстанса Picodata [default: localhost]
--port <PORT> Порт инстанса Picodata [default: 15001]
--user <USER> Имя пользователя для PG-протокола [default: admin]
--password <PASSWORD> Пароль
Для просмотра подробной справка по этим командам, включая все их возможные параметры, введите в командной строке:
silver-cli <команда> --help
Пример выгрузки результатов
Шаблон команды для выгрузки результатов расчёта в CSV-файл:
silver-cli export-result \
--host <picodata_instance_address> \
--port <picodata_instance_pg_port> \
--user <username> \
--password <password> \
--calc-id <uuid_расчета> \
--iproto-user <iproto_username> \
--iproto-password <iproto_password> \
--intermediate \
--initial-data-file <путь_к_файлу_выгружаемых_начальных_затрат> \
--file <путь_к_файлу_результатов_расчета> \
--fields <перечень_выгружаемых_полей_через_запятую> s\
--um-type-field <имя_поля_с_типом_суммы> \
--end-step-field <имя_поля_с_номером_последнего_шага_расчета>
Обязательны только первые 5 параметров (
host, port, user,
password для подключения по протоколу PostgreSQL (как и в большинстве
других команд) и calc-id — идентификатор расчета).
Алгоритм расчёта и распределения затрат¶
Примечание
Алгоритм расчёта и распределения затрат является
общим для обеих доступных моделей распределения (allocation и
final_receivers). Различия между моделями описаны ниже.
Расчёт реализован в виде алгоритма над графом, где каждая вершина представляет собой центр возникновения затрат (узел расчёта), а грани — отнесение части затрат на другой центр в соответствии с коэффициентом распределения. Ввиду того, что чаще всего в таком графе существуют циклические зависимости (когда затраты узла расчёта 1 распределяются на узел расчёта 2, а затраты узла расчёта 2, в свою очередь, распределяются на узел расчёта 1, напрямую либо через несколько промежуточных узлов расчёта), распределение затрат осуществляется в ходе последовательных итераций. Критерием остановки расчёта может служить:
- достижение заданного лимита итераций
- уменьшение общей суммы затрат к распределению на очередной итерации до суммы приемлемой общей погрешности
- уменьшение суммы входящих затрат для одного узла расчёта до суммы приемлемой погрешности для узла
Так как данные для расчёта распределены между отдельными инстансами СУБД Picodata, то выполнение итераций производится параллельно, что позволяет ускорить общее время расчёта. При этом, результаты отдельной итерации записываются в таблицу промежуточных результатов.
Примечание
Все рассчитанные суммы округляются до копеек (2 знака после запятой).
Начальные данные¶
Начальные данные объединяются в наборы, что позволяет хранить (и обрабатывать) данные для нескольких сценариев. Данные состоят из базы распределения и начальных входящих затрат, которые хранятся в следующих таблицах:
Наборы данных¶
| N | Поле | Тип | Описание |
|---|---|---|---|
| 1 | set_id | uuid | идентификатор набора данных |
| 2 | name | string | наименование набора данных |
| 3 | year | unsigned int | год периода данных |
| 4 | month | unsigned int | месяц периода данных |
База распределения¶
| N | Поле | Тип | Описание |
|---|---|---|---|
| 1 | id | string | идентификатор записи |
| 2 | set_id | uuid | идентификатор набора данных |
| 3 | sender_id | string | узел-отправитель |
| 4 | receiver_id | string | узел-получатель |
| 5 | prod_id | string | код продукции (услуги, работы) |
| 6 | base_value | decimal | значение для получателя |
Начальные затраты¶
| N | Поле | Тип | Описание |
|---|---|---|---|
| 1 | id | string | идентификатор записи |
| 2 | set_id | uuid | идентификатор набора данных |
| 3 | receiver_id | string | узел-получатель затрат |
| 4 | cost_type | string | код затраты |
| 5 | cost_sum | decimal | сумма затраты |
Этапы выполнения алгоритма¶
Подготовка к расчёту — создание узлов расчёта¶
Перед запуском расчёта для каждого узла собирается база распределения из соответствующей таблицы. При этом считается общее значение базы (OCB) и суммируется значение базы по каждому коду продукции (услуге, работе) (формула 1):
где i — порядковый номер кода продукции (услуги, работы) (далее — код выпуска),
\(СВ_i\) — сумма значений базы распределения (выпуска) этого кода продукции (работы, услуги), вычисляется по формуле 2:
где j — порядковый номер получателя кода выпуска,
\(В_j\) — значение для получателя.
Итеративное распределение затрат¶
На каждой итерации расчёта в каждом узле выполняются следующие действия:
-
выбираются входящие затраты (для первого шага — из таблицы начальных затрат, для следующих — из соответствующей текущей итерации таблицы промежуточных результатов)
- если задана сумма приемлемой погрешности для узла и общая сумма входящих затрат меньше этого значения, то распределение затрат не выполняется и расчёт для узла считается завершённым
- иначе для каждого кода затраты:
- задаются начальные значения для распределения по кодам выпуска:
- \(СРЗ\) (сумма распределяемой затраты), равная сумме затраты и
- \(БРЗ\) (база распределения затраты), равная \(ОСВ\) из формулы 1;
-
для каждого кода выпуска вычисляется часть затраты к распределению на выпуск (\(СЗВ\)):
если \(БРЗ\) равно \(СВ\) текущего кода выпуска из формулы 2, то (формула 3):
\[ СЗВ = СРЗ \]иначе (формула 4):
\[ СЗВ = { СРЗ \over БРЗ } * СВ \]После этого (формула 5):
\[ СРЗ = СРЗ - СЗВ \]и (формула 6):
\[ БРЗ = БРЗ - СВ \] -
полученное значение \(СЗВ\) распределяется по получателям:
- задаются начальные значения для распределения по получателям:
- \(СРЗП\) (сумма распределяемой затраты по получателям), равная \(СЗВ\), и
- \(БРЗП\) (база распределения затраты по получателям), равная \(В\) из формулы 2 для получателя;
-
для каждого получателя вычисляется часть затраты на получателя (\(СЗП\)):
если \(БРЗП\) равно \(В\) текущего получателя, то (формула 7):
\[ СЗП = СРЗП \]иначе (формула 8):
\[ СЗП = { СРЗП \over БРЗП } * В \] -
полученное значение \(СЗП\) увеличивает накопленную сумму затрат для сочетания “код выпуска” — “код затраты” — “получатель” и промежуточный результат для сочетания “код затраты” — “получатель”
- после окончания распределения затрат накопленные промежуточные результаты сохраняются в соответствующую следующей итерации таблицу.
- задаются начальные значения для распределения по получателям:
По окончании итерации проверяется ее порядковый номер. Если задан лимит на количество итераций и номер текущей итерации достиг его, то расчёт считается завершённым.
Также проверяется общая сумма входящих затрат для следующей итерации. Если задана сумма приемлемой общей погрешности и общая сумма затрат меньше этого значения, или нет затрат к распределению на следующей итерации, то расчёт считается завершённым.
В противном случае запускается следующая итерация расчёта.
Сохранение результатов¶
По окончании расчёта каждый узел сохраняет накопленные суммы затрат (для сочетаний “код выпуска” — “код затраты” — “получатель”) в таблицу результатов:
| N | Поле | Тип | Описание |
|---|---|---|---|
| 1 | id | string | идентификатор записи |
| 2 | calc_id | uuid | идентификатор расчёта |
| 3 | sender_id | string | узел-отправитель затрат |
| 4 | receiver_id | string | узел-получатель затрат |
| 5 | cost_type | string | код затраты |
| 6 | prod_id | string | код выпуска продукции (работы, услуги) |
| 7 | cost_sum | decimal | сумма затраты |
Модели распределения¶
Silver реализует две модели распределения, которые отличаются подходом к определению окончания расчёта и составом результирующих данных.
Алгоритм распределения одинаков в обеих моделях и описан ниже. Разберём подробнее только отличия моделей.
Стандартная модель распределения¶
Модель, используемая по умолчанию. В ней вершина графа полностью соответствует физическому подразделению (службе, отделу и т.п.), являющемуся центром возникновения затрат (ЦВЗ). Пользователю, использующему эту модель, в результатах нужны суммы и распределения входящих и исходящих затрат по каждому ЦВЗ без исключения.
В этой модели конечным получателем распределённых сумм является вершина графа, не имеющая исходящих ребер. В целях оптимизации плагин Silver не производит никаких расчётов внутри подобных вершин.
Пример ситуации для этой модели: предприятие имеет производственные подразделения и службы, выпускающие продукцию и оказывающие услуги. Продукция и услуги могут использоваться другими подразделениями, а могут продаваться внешним клиентам. Необходимо как можно точнее посчитать себестоимость каждой единицы продукции/услуги. Так как часть этой продукции/услуги может быть использована для производства других, в результате общая исходящая сумма по всем вершинам может быть больше общей суммы начальных затрат.
Модель распределения "Финальные получатели"¶
Для использования этой модели укажите значение final_receivers в
параметре calc_model в конфигурации плагина.
Несмотря на то, что алгоритм распределения затрат внутри вершины графа аналогичен используемому в стандартной модели, сама вершина может не являться физическим ЦВЗ, входящие и исходящие суммы которого обязательно должны включаться в финальные результаты.
В этой модели для каждой позиции из базы распределения вводится понятие признака окончания (флага), указание которого не обязательно. Кроме того, в отличие от стандартной модели получатель позиции базы распределения может быть пустым.
В финальные результаты по этой модели попадают любые суммы, распределённые в любой вершине графа, если:
- показатель базы распределения, по которой сумма рассчитана, помечен как финальный (указан непустой флаг). То есть стандартной является ситуация, когда только часть входящей в вершину графа суммы может быть распределена в другие вершины
- получатель показателя базы распределения, по которой сумма рассчитана, является пустым
- сумма, рассчитанная по алгоритму распределения, меньше заданной погрешности. Такие суммы в финальных результатах могут относиться на специального получателя с указанием специального флага
Пример ситуации для этой модели: полностью известна сумма, являющаяся входящей для какого-то физического подразделения. Но внутри самого подразделения эта сумма должна быть распределена по каким-то критериям согласно сложному многоступенчатому алгоритму. Тогда граф в Silver представляет собой правила этого алгоритма. Пользователя при этом интересуют только суммы, распределённые по финальным правилам. Общая сумма конечного результата должна быть равна общей сумме начальных затрат.