Перейти к содержанию

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 <имя_поля_с_номером_последнего_шага_расчета>
Команда запустит выгрузку результатов расчета. Результаты выгружаются параллельно на всех инстансах кластера Picodata, отправляются на локальный хост (откуда запущена команда) и записываются в локальные файлы.
Обязательны только первые 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):

\[ ОСВ = \sum_{i=1}^k СВ_i \]

где i — порядковый номер кода продукции (услуги, работы) (далее — код выпуска),

\(СВ_i\) — сумма значений базы распределения (выпуска) этого кода продукции (работы, услуги), вычисляется по формуле 2:

\[ СВ = \sum_{j=1}^n В_j \]

где 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 представляет собой правила этого алгоритма. Пользователя при этом интересуют только суммы, распределённые по финальным правилам. Общая сумма конечного результата должна быть равна общей сумме начальных затрат.