1. Развертывание DataReducer Console

1.1 Системные требования

  • Операционная система: Windows 7 x64 / Windows 10 x64 / DEB-based Linux x64
  • 1C:Предприятие 8 - версия 8.3.9 или старше

1.2 Схема развертывания

Процесс развертывания DataReducer Console состоит из следующих этапов:
  • Публикация интерфейса OData информационных баз на веб-сервере.
  • Запуск интерпретатора R и сервера Rserve в Docker-контейнере.
  • Установка и настройка приложения DataReducer Console.
Схема развертывания

1.3 Публикация интерфейса OData информационных баз на веб-сервере

Для интеграции с «1С:Предприятием» DataReducer Console использует протокол OData. Для работы с ним стандартный интерфейс OData каждой из информационных баз должен быть опубликован на веб-сервере.

Шаг 1. В меню Конфигуратора «Администрирование → Публикация на веб-сервере» поставьте флажок «Публиковать стандартный интерфейс OData». Более подробную информацию о настройке веб-сервера можно получить на сайте 1С:ИТС.

Шаг 2. Выберите объекты информационной базы, доступ к которым может быть предоставлен через автоматический REST-сервис. Это осуществляется с помощью типовой обработки «Настройка автоматического REST-сервиса». В некоторых конфигурациях эта обработка может быть не представлена. В этом случае для включения объектов в состав стандартного интерфейса OData следует воспользоваться методом глобального контекста УстановитьСоставСтандартногоИнтерфейсаOData(). Соответствующий код может быть выполнен во внешней обработке. Например,

&НаСервере
Процедура КомандаНаСервере()
    МассивОбъектов = Новый Массив();

    МассивОбъектов.Добавить(Метаданные.РегистрыРасчета.Начисления);
    МассивОбъектов.Добавить(Метаданные.РегистрыРасчета.Удержания);

    Для Каждого Справочник Из Метаданные.Справочники Цикл
        МассивОбъектов.Добавить(Справочник);
    КонецЦикла;

    УстановитьСоставСтандартногоИнтерфейсаOData(МассивОбъектов); 
КонецПроцедуры

1.4 Запуск интерпретатора R и сервера Rserve в Docker-контейнере

Для удобства развертывания среды R для работы с DataReducer Console подготовлен Docker-образ datareducer/rserve. Образ включает интерпретатор R, сервер Rserve, ряд других библиотек и пакетов.

«Docker — программное обеспечение для автоматизации развёртывания и управления приложениями в среде виртуализации на уровне операционной системы. Позволяет "упаковать" приложение со всем его окружением и зависимостями в контейнер, который может быть перенесён на любую Linux-систему с поддержкой cgroups в ядре, а также предоставляет среду по управлению контейнерами.» — Википедия.

Шаг 1. Скачайте с официального сайта дистрибутив Docker для вашей операционной системы и установите его.

Шаг 2. Создайте Docker-контейнер. Для этого откройте терминал (для Windows 7 - Docker Quickstart Terminal) и введите следующую команду:

$ docker run -d --name rserve -p 6311:6311 -v $(pwd):/home/docker datareducer/rserve

Docker загрузит образ datareducer/rserve и запустит его в новом контейнере.

Если указана опция -v $(pwd):/home/docker, то текущий каталог (например, домашний каталог пользователя) будет примонтирован к файловой системе контейнера в точке /home/docker. Этот каталог можно использовать для обмена файлами между R и хостом. Вместо $(pwd) может потребоваться ввести абсолютный путь к нужному каталогу хост-системы.

Опция -p 6311:6311 указывает на то, что порт 6311, который используется Rserve, должен быть проброшен в хост-систему.

Если вы используете Docker Toolbox (в Windows 7), хостом Docker-контейнеров является виртуальная машина Oracle VirtualBox, и для подключения к Rserve нужно использовать IP-адрес этой виртуальной машины (либо пробросить порты самой виртуальной машины средствами VirtualBox). Для того, чтобы узнать IP-адрес виртуальной машины в Docker Toolbox, введите команду

$ docker-machine ip default

Полученный IP-адрес далее будет использоваться для конфигурации DataReducer Console (см. п. 1.5).

Для того, чтобы убедиться, что контейнер запущен, введите команду

$ docker ps -a

Опция указывает на то, что требуется вывести список всех контейнеров, зарегистрированных в системе. Без этой опции команда «ps» отобразит только запущенные в настоящий момент контейнеры.

Шаг 3. Для повышения уровня безопасности сервер Rserve при подключении требует аутентификации. Данные для аутентификации Rservе считывает из файла /etc/R/rserve.pwd, который необходимо создать. Для этого можно воспользоваться командой «exec»:

$ docker exec rserve bash -c "echo 'change_login change_password' > /etc/R/rserve.pwd"

, где change_login и change_password — это произвольные логин и пароль.

Запуск и остановка Docker-контейнера

После того как контейнер создан и запущен командой «run», его можно остановить командой «stop» или повторно запустить командой «start»:

$ docker start rserve

Установка дополнительных пакетов R

Образ datareducer/rserve включает некоторые предустановленные пакеты R: xlsx, ggplot2, Cairo и другие. Для установки дополнительных пакетов следует воспользоваться командой «exec», например:

$ docker exec rserve R -e "install.packages('data.table')"

Для получения более подробной информации о работе с Docker обратитесь к официальной документации.


1.5 Установка и настройка DataReducer Console

После установки дистрибутива DataReducer Console перейдите в каталог приложения и отредактируйте конфигурационный файл datareducer.properties.

В Windows: %USERPROFILE%\AppData\Local\DataReducerConsole\app\datareducer.properties
В Linux: /opt/DataReducerConsole/app/datareducer.properties

В этом файле перечислены настройки подключения к Rserve и к OrientDB:

rserve-host
IP-адрес сервера Rserve. В зависимости от того, используете ли вы Docker Toolbox или нет, это может быть, соответственно, IP-адрес Docker Machine (см. п. 1.4, шаг 2), либо IP-адрес хоста, на котором установлен Docker.
rserve-user
Имя пользователя Rserve (см. п. 1.4, шаг 3)
rserve-password
Пароль пользователя Rserve (см. п. 1.4, шаг 3)
orientdb-engine
Тип сервера OrientDB. Поддерживаются значения «memory» и «remote»
orientdb-server
IP-адрес удаленного сервера OrientDB. Игнорируется, если значение параметра orientdb-engine равно «memory»
orientdb-user
Имя пользователя OrientDB
orientdb-password
Пароль пользователя OrientDB

Значения по умолчанию параметров orientdb-* в общем случае изменять не требуется.

Запустите DataReducer Console и проверьте подключение к Rserve. Для этого в главном меню программы выберите «Инструменты → Проверить подключение к Rserve». При успешном подключении вы увидите версию R. В противном случае будет выведено сообщение об ошибке.

Проверка подключения

2. Работа с DataReducer Console

2.1 Подключение информационных баз и загрузка метаданных

В DataReducer Console вы можете одновременно работать с данными нескольких информационных баз. Для того, чтобы открыть окно подключения информационной базы, выберите пункт главного меню «Правка → Добавить базу 1С» или нажмите соответствующую кнопку на панели списка информационных баз.

Окно подключения ИБ

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

Форма списка ИБ

В дереве метаданных отображаются только те объекты, которые пользователь включил в состав стандартного интерфейса OData данной информационной базы (см. п. 1.3).


2.2 Интерфейс главного окна программы

Главное окно программы
  1. Список информационных баз
  2. Дерево метаданных
  3. Вкладка скрипта R
  4. Наборы данных скрипта R
  5. Область вывода сообщений
  6. Таблица данных
  7. Область вывода графики

2.3 Формирование наборов данных

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

Для создания набора данных, содержащего данные объектов информационной базы «1С:Предприятия», воспользуйтесь контекстным меню дерева метаданных.

Создание набора данных

Выбранный объект будет добавлен в наборы данных скрипта R, вкладка которого открыта и активна в настоящий момент.

Двойным кликом по строке списка наборов данных скрипта R откройте окно созданного набора для его редактирования.

Доступные настройки зависят от типа объекта, которому соответствует набор данных.

Ниже приведены описания общих для всех объектов настроек.

Панель настроек и параметров

Панель настроек и параметров

Наименование набора данных — идентификатор, по которому будет осуществляться обращение к набору данных в теле скрипта R.

Время кэширования (минут) — время хранения результатов выполнения запроса в кэше. Устанавливается отдельно для каждого набора данных. Например, для Констант имеет смысл установить более продолжительное время кэширования.

Вы можете отключить кэширование данного набора данных, введя в это поле значение «0».

Учитывать ограничения доступа — выборка только тех объектов информационной базы, к которым пользователь имеет доступ.

Панель выбора полей (измерений)

Панель выбора полей (измерений)

По умолчанию в запрос включаются все поля объекта. Для ограничения их состава оставьте в правой таблице только выбранные поля.

Отметьте флажок «Представление», если вы хотите, чтобы в набор данных было включено представление поля. Например, для поля «Организация_Key» с типом GUID в набор данных будет включена колонка с именем «Организация____Presentation», содержащая наименования организаций.

Панель отбора

Панель отбора

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

Фильтры могут быть сгруппированы. Для этого выделите два или более фильтра с помощью клавиши «Ctrl» и нажмите кнопку «Сгруппировать».

Колонки:

  1. Колонка группы — логический оператор, выбирается из выпадающего списка из значений «И», «Или». Может принимать значение «Не», если логическое выражение инвертировано. Для инверсии фильтра (или группы) выделите строку фильтра (или группы) и нажмите кнопку «Инвертировать».
  2. Поле — выбирается из выпадающего списка. После имени поля в квадратных скобках указан его тип. Для обозначения полей составного типа к имени типа добавляется символ «c», например, «[string, c]». (Для полей составных типов предусмотрен специальный формат значения, см. далее).
  3. Оператор — оператор сравнения. Выбирается из выпадающего списка.
  4. Значение — вводится вручную в соответствии с типом поля. Для полей с типом «boolean» принимаются значения «true» или «false». Значения полей составных типов вводятся с использованием функции «cast». Например, cast(guid'd341d2be-b3b1-11dc-a100-0011d85708ff', 'Catalog_СтатьиДвиженияДенежныхСредств'). Предусмотрен графический инструмент ввода значений полей составных типов.

  5. Ввоз значения составного типа

    Вместо значения в колонку значения поля любого типа может быть введено имя параметра (см. п. 2.4).

  6. Комментарий — произвольный комментарий к фильтру. Например, расшифровка значения с типом GUID.

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

Окно набора данных

Сформированный URL-адрес ресурса выводится в области вывода сообщений в главном окне программы.


2.4 Параметры скрипта R

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

Имена параметров должны начинаться с символа «&». Например, «&periodBegin».

Значения параметров вводятся на панели «Параметры» формы скрипта R.

Список параметров скрипта

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

Пространство имён параметров общее для всех наборов данных одного и того же скрипта.

Предопределенные параметры

&name
наименование скрипта
&description
описание скрипта
&resourceName
имя ресурса (для веб-приложения)
&requestId
идентификатор запроса, генерируется при его обработке случайным образом (для веб-приложения)

2.5 Конструкции языка R для выполнения типовых задач

Вывод результата выполнения скрипта (таблицы данных)

DataReducer Console выводит в главном окне программы ту таблицу данных, идентификатор которой является последним оператором скрипта R.

Вывод текстовой информации

Если вместо таблицы данных требуется вывести форматированный текст (например, описание линейной модели), нужно воспользоваться функцией capture.output(). Например, вместо summary(model) следует ввести:

paste(capture.output(print(summary(model))), collapse='\n')

Чтение файлов Excel

Docker-образ datareducer/rserve содержит пакет xlsx для работы с таблицами Excel. Для чтения файла Excel воспользуйтесь функцией read.xlsx(). Например,

library(xlsx)
plan <- read.xlsx('/home/docker/План_1кв.xlsx', 1)

Первый аргумент функции в примере — путь к файлу в каталоге /home/docker Docker-контейнера (см. п. 1.4). Второй аргумент — индекс листа.

Запись в файл Excel

Для записи таблицы данных в файл Excel воспользуйтесь функцией write.xlsx(). Например,

library(xlsx)
write.xlsx(pf, '/home/docker/ПланФакт.xlsx', row.names = FALSE)

Вывод диаграммы на экран

Для работы с графикой используется пакет Cairo. Для вывода диаграммы на экран после функции print() введите dev.off(). Также рекомендуется указать используемый в диаграмме шрифт:

CairoFonts(regular='Free Helvetian:style=Regular')
print(chart)
dev.off()

Ширина и высота диаграммы вводится в соответствующих полях области вывода графики главного окна программы.

Для вывода списка шрифтов, установленных в Docker-контейнере rserve, введите в терминале команду $ docker exec rserve "fc-list"

Запись диаграммы в файл

Для этого воспользуйтесь функцией CairoPNG(), после которой, так же как и для вывода графики на экран, нужно ввести print() и dev.off():

CairoPNG('/home/docker/chart.png', width=520, height=360)
print(chart)
dev.off()

Ширина и высота диаграммы в этом случае вводятся в качестве аргументов функции CairoPNG().


3. Примеры использования DataReducer Console

3.1 Пример 1: Агрегация данных из разных источников

Требуется выполнить план-фактный анализ поступлений денежных средств компании за квартал. Компания состоит из двух юридических лиц — организаций «УноФарма» и «ПортоФарма». Бухгалтерский учёт организаций ведётся в двух разных информационных базах «1С:Бухгалтерия предприятия 3.0».

Отчет Факт УноФарма Отчет Факт ПортоФарма

Запланированные значения поступлений необходимо получить из таблицы Excel, в которой отражены суммарные данные по всем организациям.

Отчет План

Шаги решения поставленной задачи в программе «DataReducer Console»

  1. Добавляем настройки подключения к информационным базам «УноФарма» и «ПортоФарма». Интерфейс OData этих баз предварительно должен быть опубликован на веб-сервере и настроен в соответствии с документацией платформы «1С:Предприятие» (см. п. 1.3). С помощью «DataReducer Console» можно одновременно работать с данными любого количества информационных баз. Список подключенных баз отображается в главном окне программы (см. п. 2.2).
  2. После подключения информационной базы, «DataReducer Console» выводит дерево её метаданных. Дерево метаданных включает все сущности, доступные через интерфейс OData (справочники, регистры, виртуальные таблицы и пр.). Для свойств сущностей выводится их тип. Для свойств с ссылочным типом выводится связанная сущность.
  3. Создаём новый скрипт R и открываем его. Каждый скрипт открывается в отдельной вкладке.
  4. Находим в дереве метаданных информационной базы «УноФарма» виртуальную таблицу оборотов регистра бухгалтерии «Хозрасчётный» и через контекстное меню добавляем её в наборы данных скрипта R. Повторяем для информационной базы «ПортоФарма». Любой набор данных можно открыть в отдельном окне и загрузить данные для просмотра.

  5. Окно набора данных
  6. Поочерёдно открываем окна созданных наборов данных и вводим настройки запросов. Перечень доступных настроек зависит от типа объекта, которому соответствует набор данных. Начало и конец периода получения оборотов регистра бухгалтерии «Хозрасчетный» задаём в виде параметров «&periodBegin» и «&periodEnd». Значения этих параметров будут общими для всех наборов данных скрипта R (см. п. 2.4).
  7. Пишем код на языке R (см. листинг). Обращение к наборам данных осуществляется по их именам.
  8. Выполняем скрипт. На экран выводятся сообщения о ходе выполнения, в том числе сформированные запросы REST-сервису «1С:Предприятия». В области вывода графики выводится построенная диаграмма. Результаты выполнения скрипта (таблицу данных и диаграмму) можно сохранить в файлы, используя методы языка R (см. п. 2.5).

Листинг

# Обрабатываем данные информационной базы ООО "УноФарма".

# Создаём таблицу данных, выбирая нужные нам поля набора данных "AccountingRegister_Хозрасчетный_Turnover1" 
# (соответствующего виртуальной таблице оборотов регистра бухгалтерии "Хозрасчетный").

ib1 <- AccountingRegister_Хозрасчетный_Turnover1[c('ExtDimension1____Presentation',
     'ExtDimension1_Type', 'ExtDimension2____Presentation', 'ExtDimension2_Type', 'СуммаTurnoverDr')]

# Статья движения д/с может быть записана в разные реквизиты - Субконто1 или Субконто2.
# Разбиваем данные на два набора, соответствующих первому и второму случаю.
# Затем, объединяя эти наборы, получаем таблицу данных с отдельным столбцом статей движения д/с.

ib1_1 <- subset(ib1, ib1$ExtDimension1_Type == 'StandardODATA.Catalog_СтатьиДвиженияДенежныхСредств',
     select=c(ExtDimension1____Presentation, СуммаTurnoverDr))

ib1_2 <- subset(ib1, ib1$ExtDimension2_Type == 'StandardODATA.Catalog_СтатьиДвиженияДенежныхСредств',
     select=c(ExtDimension2____Presentation, СуммаTurnoverDr))

fact1 <- merge(ib1_1, ib1_2, by.x=c('ExtDimension1____Presentation', 'СуммаTurnoverDr'),
     by.y=c('ExtDimension2____Presentation', 'СуммаTurnoverDr'), all = TRUE)

# Выполняем те же операции для информационной базы ООО "ПортоФарма".

ib2 <- AccountingRegister_Хозрасчетный_Turnover2[c('ExtDimension1____Presentation',
     'ExtDimension1_Type', 'ExtDimension2____Presentation', 'ExtDimension2_Type', 'СуммаTurnoverDr')]

ib2_1 <- subset(ib2, ib2$ExtDimension1_Type == 'StandardODATA.Catalog_СтатьиДвиженияДенежныхСредств',
     select=c(ExtDimension1____Presentation, СуммаTurnoverDr))

ib2_2 <- subset(ib2, ib2$ExtDimension2_Type == 'StandardODATA.Catalog_СтатьиДвиженияДенежныхСредств',
     select=c(ExtDimension2____Presentation, СуммаTurnoverDr))

fact2 <- merge(ib2_1, ib2_2, by.x=c('ExtDimension1____Presentation', 'СуммаTurnoverDr'),
     by.y=c('ExtDimension2____Presentation', 'СуммаTurnoverDr'), all = TRUE)

# Объединяем данные двух информационных баз и суммируем значения поступлений по статьям.

fact <- merge(fact1, fact2, , all=TRUE)

if (nrow(fact) > 0) fact <- aggregate(fact[, 2], by=list(fact[, 1]), sum)

# Переименовываем столбцы.

names(fact)[1] <- 'СтатьяДДС'
names(fact)[2] <- 'Факт'

# Считываем фактические данные поступлений д/с из файла Excel.
# Файл расположен в каталоге, примонтированном к Docker-контейнеру сервиса Rserve в точке /home/docker.

library(xlsx)
plan <- read.xlsx('/home/docker/План_1кв.xlsx', 1)

# Объединяем таблицы плановых и фактических данных.

pf <- merge(plan, fact, by=1, all=TRUE)

# Рассчитываем абсолютные и относительные отклонения фактических значений от плановых
# и помещаем результаты в новые колонки.

pf$ОтклонениеАбс <- pf$Факт - pf$План
pf$ОтклонениеОтн <- round((pf$Факт - pf$План) / pf$Факт, digits = 2)

# Подготавливаем данные для построения диаграммы.

# Приводим таблицу данных к нужному формату 
# (функция melt() преобразует данные в такой формат, что переменные "План" и "Факт"
# располагаются в собственных строках вместе с переменными "СтатьяДДС", их идентифицирующими.

library(reshape2)
names(pf)[1] <- 'СтатьяДДС'
pf.m <- melt(pf[,1:3], id.var='СтатьяДДС')

# Для экономии места на диаграмме разбиваем названия статей по словам.

pf.m$СтатьяДДС <- gsub("\\s","\n", pf.m$СтатьяДДС)

# Строим столбчатую диаграмму. Указываем вид диаграммы - с группировкой, 
# горизонтальное расположение и размер шрифта.

library(ggplot2)
chart <- ggplot(pf.m, aes(x = СтатьяДДС, y = value, fill = variable)) + geom_bar(stat='identity', position = 'dodge') +
    coord_flip() + theme(text = element_text(size=13))

# Указываем шрифт, используемый в диаграмме.
# Шрифт должен быть установлен в системе (в Docker-контейнере сервиса Rserve)

CairoFonts(regular='Free Helvetian:style=Regular')

# Выводим диаграмму на экран.

print(chart)
dev.off()

# Создаем каталог для хранения файлов в точке монтирования /home/docker

analysisDir <- '/home/docker/analysis'
dir.create(analysisDir)

# Записываем диаграмму в файл.

chartFile <- paste(analysisDir, 'chart.png', sep='/')
CairoPNG(chartFile, width =520, height=360)
print(chart)
dev.off()

# Записываем таблицу данных в файл Excel.

xlsxFile <- paste(analysisDir, 'ПланФакт.xlsx', sep='/')
write.xlsx(pf, xlsxFile, row.names = FALSE)

# Выводим таблицу данных.
pf

Результат

На данном примере были продемонстрированы основные инструменты программы «DataReducer Console» для импорта данных информационных баз «1С:Предприятия» и некоторые методы языка R для обработки этих данных. Были получены и агрегированы данные из трёх разных источников: двух информационных баз «1С: Бухгалтерия предприятия 3.0» и файла Excel. С помощью пакета ggplot2 была построена столбчатая диаграмма, отображающая отклонения фактических значений показателей от плановых.

Диаграмма

3.2 Пример 2: Регрессионный анализ данных информационной базы

Планово-экономический отдел ПАО «Астросбыт» предполагает, что между прибылью от продаж и дебиторской и кредиторской задолженностями компании существует зависимость, которую можно использовать для прогнозирования значения показателя прибыли от продаж. Требуется оценить эту зависимость.

Для построения регрессионной модели воспользуемся данными учета компании за 16 предыдущих кварталов. Эти данные мы получим из информационной базы «1С:ERP Управление предприятием 2».

Введём обозначения переменных и определим источники данных.

prib — Прибыль от продаж (зависимая переменная)

Прибыль от продаж = Выручка от продаж - Себестоимость продаж - Коммерческие и управленческие расходы

Источники данных: обороты регистров накопления «Выручка и себестоимость продаж» и «Прочие расходы».

deb — Дебиторская задолженность (независимая переменная)

Источники данных: остатки регистра накопления «Расчеты с клиентами по документам».

kred — Кредиторская задолженность (независимая переменная)

Источники данных: остатки регистра накопления «Расчеты с поставщиками по документам».

Таким образом, каждому кварталу будет соответствовать четыре набора данных по числу запросов к регистрам информационной базы. Необходимо получить данные по 16-ти периодам, значит, всего будет выполнено 64 запроса.

Формируем наборы данных, используя дерево метаданных информационной базы и конструкторы запросов.

Наборы данных

Наблюдение по каждому кварталу и итоговую таблицу данных для анализа создаём следующим образом:

Q1_2014 <- data.frame(
        prib  = Q1_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q1_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q1_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q1_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q1_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q2_2014 <- data.frame(
        prib  = Q2_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q2_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q2_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q2_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q2_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
...
df <- rbind(Q1_2014, Q2_2014, Q3_2014, Q4_2014, Q1_2015, Q2_2015, Q3_2015, Q4_2015,
            Q1_2016, Q2_2016, Q3_2016, Q4_2016, Q1_2017, Q2_2017, Q3_2017, Q4_2017)

«Q1_2014_ВыручкаИСебестоимость», «Q1_2014_ПрочиеРасходы» и пр. - это имена, которые мы дали наборам данных, соответствующим виртуальным таблицам регистров накопления. «СуммаВыручкиTurnover», «СтоимостьTurnover» и пр. - имена полей этих таблиц, формируемые платформой 1С.

Смотрим полученную таблицу данных:

Таблица данных

Предварительно оценим нашу модель:

model <- lm(data=df, prib~deb+kred)
paste(capture.output(print(summary(model))), collapse='\n')
Линейная модель

Как видно из последнего столбца таблицы, коэффициенты при переменных deb и kred статистически значимо отличаются от нуля при p < 0.01 и p < 0.001, соответственно. Это указывает на то, что и дебиторская и кредиторская задолженности влияют на показатель прибыли от продаж. Взятые вместе, они на 57% описывают изменения показателя (Multiple R-squared: 0.571).

Теперь проверим данные и посмотрим, можем ли мы нашу модель улучшить.

Для этого воспользуемся методами, реализованными в пакете car (пакет уже установлен в Docker-контейнере rserve).

Проверим, что ошибки регрессии нормально распределены (одна из предпосылок линейной регрессии, которые должны выполняться, чтобы мы могли считать модель адекватной). Выполним это графически, построив Q-Q график, или график Квантиль-Квантиль:

library(car)

qq <- qqPlot(model, labels = row.names(df), simulate = TRUE, main = "Q-Q plot")
print(qq)
dev.off()
График Квантиль-Квантиль

На графике хорошо видно, что одно из наблюдений выпадает из доверительных границ (изображенных пунктирными линиями) — это т. н. «выброс», т. е. наблюдение, которое плохо предсказывается моделью.

Определяем индекс этого наблюдения и удаляем его из нашего набора, после чего снова оцениваем модель:

paste(capture.output(print(outlierTest(model))), collapse='\n')
df2 <- df[-c(12),]

model <- lm(data=df2, prib~deb+kred)
paste(capture.output(print(summary(model))), collapse='\n')

Как мы видим, после удаления «выброса» значимость коэффициентов при независимых переменных увеличилась и модель в целом стала лучше соответствовать данным (Multiple R-squared: 0.793).

Проверим выполнение остальных предпосылок линейной регрессии.

Проверим независимость остатков при помощи теста Дарбина - Уотсона:

paste(capture.output(print(durbinWatsonTest(model))), collapse='\n')
Тест Дарбина - Уотсона

Высокое значение p-value говорит о независимости остатков, т. е. предпосылка выполняется.

Проверим линейность связи между зависимой и независимыми переменными при помощи диаграмм компонент и остатков:

cr <- crPlots(model)
print(cr)
dev.off()
Диаграммы компонент и остатков

Диаграммы подтверждают, что требование линейности соблюдено.

Гомоскедастичность (однородность дисперсии) проверим также графически:

sl <- spreadLevelPlot(model)
print(sl)
dev.off()
Проверка на гомоскедастичность

Мы видим, что требование гомоскедастичности также выполняется, об этом говорит близкая к горизонтальной прямая на графике.

Таким образом, все предпосылки линейной регрессии выполняются. Мы можем перепроверить их выполнение при помощи функции gvlma() из пакета gvlma

library(gvlma)
gvmodel <- gvlma(model)
paste(capture.output(print(summary(gvmodel))), collapse='\n')

Смотрим на столбец «Decision» и ещё раз убеждаемся, что наши данные удовлетворяют всем предпосылкам, лежащим в основе МНК-регресии, то-есть наша модель статистически адекватна.

Воспользуемся моделью для предсказания прибыли от продаж в следующем квартале. Подставим плановые значения дебиторской и кредиторской задолженностей.

nd <- data.frame(deb=84112200, kred=64817200)
paste(capture.output(print(predict(model, newdata = nd, interval = "prediction"))), collapse='\n')

Итак, в соответствии с нашим прогнозом, при значениях дебиторской и кредиторской задолженностей, равных, соответственно, 84112200 руб. и 64817200 руб., прибыль от продаж будет равна 4813612 руб. Но, как мы видим, доверительный интервал довольно широкий, т. е. данный прогноз нельзя назвать точным.

Пример целиком

# Получаем значения показателей для каждого квартала

Q1_2014 <- data.frame(
        prib  = Q1_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q1_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q1_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q1_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q1_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q2_2014 <- data.frame(
        prib  = Q2_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q2_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q2_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q2_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q2_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q3_2014 <- data.frame(
        prib  = Q3_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q3_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q3_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q3_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q3_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q4_2014 <- data.frame(
        prib  = Q4_2014_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q4_2014_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q4_2014_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q4_2014_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q4_2014_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q1_2015 <- data.frame(
        prib  = Q1_2015_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q1_2015_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q1_2015_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q1_2015_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q1_2015_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q2_2015 <- data.frame(
        prib  = Q2_2015_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q2_2015_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q2_2015_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q2_2015_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q2_2015_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q3_2015 <- data.frame(
        prib  = Q3_2015_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q3_2015_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q3_2015_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q3_2015_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q3_2015_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q4_2015 <- data.frame(
        prib  = Q4_2015_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q4_2015_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q4_2015_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q4_2015_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q4_2015_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q1_2016 <- data.frame(
        prib  = Q1_2016_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q1_2016_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q1_2016_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q1_2016_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q1_2016_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q2_2016 <- data.frame(
        prib  = Q2_2016_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q2_2016_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q2_2016_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q2_2016_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q2_2016_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q3_2016 <- data.frame(
        prib  = Q3_2016_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q3_2016_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q3_2016_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q3_2016_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q3_2016_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q4_2016 <- data.frame(
        prib  = Q4_2016_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q4_2016_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q4_2016_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q4_2016_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q4_2016_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q1_2017 <- data.frame(
        prib  = Q1_2017_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q1_2017_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q1_2017_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q1_2017_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q1_2017_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q2_2017 <- data.frame(
        prib  = Q2_2017_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q2_2017_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q2_2017_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q2_2017_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q2_2017_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q3_2017 <- data.frame(
        prib  = Q3_2017_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q3_2017_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q3_2017_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q3_2017_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q3_2017_РасчетыСПоставщиками[1, c("ДолгBalance")])
)
Q4_2017 <- data.frame(
        prib  = Q4_2017_ВыручкаИСебестоимость[1, c("СуммаВыручкиTurnover")] -
                Q4_2017_ВыручкаИСебестоимость[1, c("СтоимостьTurnover")] -
                Q4_2017_ПрочиеРасходы[1, c("СуммаTurnover")],
        deb  = Q4_2017_РасчетыСКлиентами[1, c("ДолгBalance")],
        kred = abs(Q4_2017_РасчетыСПоставщиками[1, c("ДолгBalance")])
)

# Объединяем все наблюдения в одну таблицу

df <- rbind(Q1_2014, Q2_2014, Q3_2014, Q4_2014, Q1_2015, Q2_2015, Q3_2015, Q4_2015,
        Q1_2016, Q2_2016, Q3_2016, Q4_2016, Q1_2017, Q2_2017, Q3_2017, Q4_2017)

# Предварительно оцениваем линейную модель

model <- lm(data=df, prib~deb+kred)
paste(capture.output(print(summary(model))), collapse='\n')

# Проверяем, что ошибки регрессии нормально распределены

library(car)

qq <- qqPlot(model, labels = row.names(df), simulate = TRUE, main = "Q-Q plot")
print(qq)
dev.off()

# Определяем индекс "выброса"

paste(capture.output(print(outlierTest(model))), collapse='\n')

# Удаляем "выброс" из таблицы

df2 <- df[-c(12),]

# Создаем и оцениваем новую модель

model <- lm(data=df2, prib~deb+kred)
paste(capture.output(print(summary(model))), collapse='\n')

# Проверяем независимость остатков при помощи теста Дарбина - Уотсона

paste(capture.output(print(durbinWatsonTest(model))), collapse='\n')

# Проверяем линейность связи между зависимой и независимыми переменными
# при помощи диаграмм компонент и остатков

cr <- crPlots(model)
print(cr)
dev.off()

# Проверяем гомоскедастичность (однородность дисперсии)

sl <- spreadLevelPlot(model)
print(sl)
dev.off()

# Перепроверяем все предпосылки МНК-регрессии

library(gvlma)
gvmodel <- gvlma(model)
paste(capture.output(print(summary(gvmodel))), collapse='\n')

# Выводим прогноз прибыли от продаж и предиктивные доверительные интервалы

nd <- data.frame(deb=84112200, kred=64817200)
paste(capture.output(print(predict(model, newdata = nd, interval = "prediction"))), collapse='\n')

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

  • Лысенко М.В., Лысенко Ю.В., Якушев А.А., Согрина Н.С. «Cтатистический анализ дебиторской и кредиторской задолженности при оперативном прогнозировании прибыли от продаж» // Фундаментальные исследования. – 2016. – № 12-4. – С. 884-890
  • Цикл видео-лекций Демешева Б.Б. по курсу Эконометрики
  • Кабаков Р.И. «R в действии. Анализ и визуализация данных в программе R» / пер. с англ. Полины А. Волковой. – М.: ДМК Пресс, 2014. – 588 с.: ил.

Выводы по использованию программы DataReducer Console:

Как показывает этот пример, при большом количестве наборов данных, их извлечение из информационной базы 1C по протоколу OData может стать достаточно трудоёмкой задачей. Это может быть оправдано в следующих случаях:

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

4. Развертывание веб-приложения DataReducer

4.1 Системные требования

  • Операционная система: Windows 7 x64 / Windows 10 x64 / DEB-based Linux x64
  • 1C:Предприятие 8 - Версия 8.3.9

4.2 Настройка окружения и установка веб-приложения

Если ранее вы уже работали с DataReducer Console, то у вас уже настроен интерфейс OData информационных баз «1С:Предприятия» и установлен Docker.

Схема развертывания веб-приложения

Ниже приведены все действия, которые необходимо выполнить для начала работы с веб-приложением DataReducer.

  1. Опубликуйте интерфейс OData информационных «1С:Предприятия» баз на веб-сервере (см. раздел 1.3).
  2. Скачайте с официального сайта последнюю версию контейнера сервлетов Apache Tomcat и установите его.
  3. Отредактируйте файл конфигурации conf/tomcat-users.xml, добавив роль «DataReducerAdministrator» и пользователя с этой ролью.
    <?xml version="1.0" encoding="UTF-8"?>
    
    <tomcat-users xmlns="http://tomcat.apache.org/xml"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
                  version="1.0">
    
      <role rolename="DataReducerAdministrator"/>  
      <user username="admin" password="admin" roles="DataReducerAdministrator"/>
    
    </tomcat-users>
    Подробнее о механизмах аутентификации Apache Tomcat читайте в документации.
  4. Поместите архив веб-приложения rwa.war в каталог webapps контейнера сервлетов.
  5. Запустите Apache Tomcat и перейдите по адресу http://localhost:8080/rwa, чтобы убедиться, что веб-приложение работает. При этом потребуется ввести имя и пароль пользователя, которого вы создали на шаге 3.

    Открыть тестовые данные iris ещё нельзя, так как не указаны настройки подключения к Rserve.
  6. Запустите интерпретатор R и сервер Rserve в Docker-контейнере (см. раздел 1.4.). Для того, чтобы файлы, созданные R, были доступны веб-приложению, его каталог должен быть примонтирован к файловой системе Docker-контейнера. Это выполняется при создании контейнера. Если он уже создан, его необходимо пересоздать:
  7. $ docker stop rserve && docker rm rserve
    $ docker run -d --name rserve -p 6311:6311 -v $(pwd):/home/docker -v /opt/apache-tomcat-9.0.5/webapps/rwa/files:/home/rwa datareducer/rserve
  8. Отредактируйте файл настроек приложения /rwa/WEB-INF/datareducer.properties (см. раздел 1.5).
  9. Перезапустите Apache Tomcat, перейдите по адресу http://localhost:8080/rwa и откройте тестовый ресурс iris

5. Работа с веб-приложением DataReducer

5.1 Конфигурация веб-приложения

Основной конфигурационный файл datareducer.conf веб-приложения располагается в каталоге rwa/WEB-INF и создаётся с помощью программы DataReducer Console (см. разделы 1-3).


Для того, чтобы результаты выполнения скрипта R были доступны через веб-приложение, установите галочку «Веб-доступ» и задайте имя ресурса.

После создания конфигурации сохраните её файл в каталоге rwa/WEB-INF и перезапустите Apache Tomcat.

5.2 Обращение к ресурсам

Все скрипты, на вкладке «Веб-доступ» которых установлена соответствующая галочка, выводятся в списке ресурсов на главной странице веб-приложения (при наличии у пользователя прав на их просмотр).

Обращение к ресурсам осуществляется по их именам, заданным в DataReducer Console. Например, http://localhost:8080/rwa/analysis1

Если скрипт содержит параметры (см. раздел 2.4), их значения можно передать в запросе. Например, http://localhost:8080/rwa/analysis1?periodBegin=2017-01-01T00%3A00%3A00&periodEnd=2017-03-31T23%3A59%3A59

Данные ресурса можно получить в трёх различных форматах: HTML, XML или JSON. По умолчанию данные возвращаются в формате HTML. Для получения XML или JSON соответствующий тип содержимого нужно указать в заголовке «Accept» запроса.

5.3 Шаблон вывода данных ресурса

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

Веб-приложение DataReducer использует шаблонизатор FreeMarker.

В теле шаблона можно использовать параметры скрипта R (см. раздел 2.4) в соответствии с синтаксисом FreeMarker. Например,

Период: с ${periodBegin?keep_before('T')} по ${periodEnd?keep_before('T')}

, где periodBegin и periodEnd — это имена параметров скрипта R. В данном примере на странице будут выведены даты начала и конца периода с отброшенным временем. О синтаксисе FreeMarker можно прочесть в официальной документации шаблонизатора.

Помимо параметров скрипта R в теле шаблона можно использовать предопределенные параметры:

  • ${name} — наименование скрипта;
  • ${description} — описание скрипта;
  • ${resourceName} — имя ресурса;
  • ${requestId} — идентификатор запроса, генерируется при его обработке случайным образом.

5.4 Разграничение доступа к ресурсам

Для каждого ресурса можно указать роли пользователей, которые должны иметь к нему доступ. Список ролей находится на вкладке «Веб-доступ» программы DataReducer Console.

Пользователю с ролью «DataReducerAdministrator» доступны все ресурсы (см. раздел 5.2).

Процедура добавления новой роли при использовании способа аутентификации UserDatabaseRealm:

  1. Отредактируйте файл конфигурации conf/tomcat-users.xml.
    <?xml version="1.0" encoding="UTF-8"?>
    
    <tomcat-users xmlns="http://tomcat.apache.org/xml"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
                  version="1.0">
    
      <role rolename="DataReducerAdministrator"/>
      <role rolename="FinanceDirector"/>
    
      <user username="admin" password="admin" roles="DataReducerAdministrator"/>
      <user username="ivanov" password="123456" roles="FinanceDirector"/>
    
    </tomcat-users>
  2. Добавьте информацию о новой роли в файл rwa/WEB-INF/web.xml. Роли доступа к ресурсу назначаются при создании конфигурации в программе DataReducer Console, но если скрипт генерирует файлы, к которым будет открыт доступ по сети (например, изображения), права на них должны быть установлены отдельно.
    <?xml version="1.0" encoding="UTF-8"?>
    ...
         <security-constraint>
            <web-resource-collection>
                <web-resource-name>Список ресурсов</web-resource-name>
                <description>Должен быть доступен всем авторизованным пользователям.
                 Роли доступа к конкретным ресурсам указываются в datareducer.conf</description>
                <url-pattern>/</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>DataReducerAdministrator</role-name>
                <role-name>FinanceDirector</role-name>
            </auth-constraint>
        </security-constraint>
    
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Каталог файлов</web-resource-name>
                <url-pattern>/files/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>DataReducerAdministrator</role-name>
            </auth-constraint>
        </security-constraint>
    
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Файлы отчета по анализу поступлений</web-resource-name>
                <url-pattern>/files/analysis1/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>DataReducerAdministrator</role-name>
                <role-name>FinanceDirector</role-name>
            </auth-constraint>
        </security-constraint>
    ...
        <security-role>
            <description>Финансовый директор</description>
            <role-name>FinanceDirector</role-name>
        </security-role>
        
    </web-app>

6. Пример использования веб-приложения DataReducer

Откроем доступ по сети к результатам анализа данных из первого примера (см. раздел 3.1).

В программе DataReducer Console для данного скрипта устанавливаем галочку «Веб-доступ» и назначаем имя ресурса «analysis1». Сохраняем новую конфигурацию datareducer.conf в каталоге rwa/WEB-INF веб-приложения и перезагружаем Apache Tomcat.

Новый ресурс появляется в списке ресурсов на главной странице веб-приложения.


Переходим по ссылке с именем скрипта и получаем таблицу данных, которую он генерирует, в формате HTML.


Добавим на страницу ресурса период отчета, ссылку на скачивание данных в формате Excel и сгенерированную в R диаграмму. Для этого внесём изменения в скрипт и шаблон страницы ресурса.

(...)

# Создаем каталог для хранения файлов в точке монтирования /home/rwa Docker-контейнера,
# соответствующей каталогу /opt/apache-tomcat-9.0.5/webapps/rwa/files
# веб-приложения

resourceDir <- '/home/rwa/&resourceName'
requestDir <- paste(resourceDir, '&requestId', sep='/')
dir.create(resourceDir)
dir.create(requestDir)

# Записываем диаграмму в файл.

chartFile <- paste(requestDir, 'chart.png', sep='/')
CairoPNG(chartFile, width =520, height=360)
print(chart)
dev.off()

# Записываем таблицу данных в файл Excel.

xlsxFile <- paste(requestDir, 'ПланФакт.xlsx', sep='/')
write.xlsx(pf, xlsxFile, row.names = FALSE)

# Выводим таблицу данных.
pf

Теперь после выполнения скрипта в каталоге rwa/files веб-приложения будет создан каталог ресурса с его именем «analysis1», а в нём - подкаталог запроса с названием, сгенерированным случайным образом.

Файлы диаграммы и Excel будут сохранены в подкаталоге запроса и ссылки на них можно добавить на веб-страницу ресурса.

В программе DataReducer Console снимаем галочку «Шаблон по умолчанию» и вносим изменения в шаблон.

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>${name}</title>

    <link href="/rwa/css/bootstrap.min.css" rel="stylesheet">
    <link href="/rwa/css/ie10-viewport-bug-workaround.css" rel="stylesheet">

    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>

  <body>
  
    <div class="container">
        <div class="page-header">
            <h3>${name}</h3>
        </div>
        <p><i>${description}</i></p>
        <p><i>Период: с ${periodBegin?keep_before('T')} по ${periodEnd?keep_before('T')}</i></p>

        <#if dataFrame?size != 0>
        <p><a href="/rwa/files/${resourceName}/${requestId}/ПланФакт.xlsx">Сохранить в Excel</a></p>

        <table class="table table-condensed">
            <thead>
                <tr>
                    <#list dataFrame[0]?keys as column>
                    <th>${column}</th>
                    </#list>
                </tr>
            <thead>
            <#list dataFrame as record>
                <tr>
                    <#list record?keys as column>
                    <td>${record[column]}</td> 
                    </#list>
                </tr>
            </#list>
        </table>

        <p><img src="/rwa/files/${resourceName}/${requestId}/chart.png" class="img-responsive"></p>
        <hr>

        </#if>
    </div>

    <script src="/rwa/js/jquery-3.1.1.min.js"></script>
    <script src="/rwa/js/bootstrap.min.js"></script>
    <script src="/rwa/js/ie10-viewport-bug-workaround.js"></script>
    
  </body>
</html>

И в скрипте и в шаблоне используются имена параметров resourceName и requestId, которые являются элементами адреса каталога файлов веб-приложения, в данном случае, каталога rwa/files/analysis1/8b46c111e05b5b3bae7c7d6cb1f03cb3cf6eed9b. Для каждой роли пользователей ресурса analysis1 в файле rwa/WEB-INF/web.xml нужно установить права на этот каталог (см. раздел 5.4).

После замены файла конфигурации rwa/WEB-INF/datareducer.conf и перезапуска Apache Tomcat мы увидим страницу ресурса с внесенными нами изменениями.


О логотипе

Логотип программы — это видоизмененное изображение логотипа R, автором которого является организация R Foundation. Изменение заключается в замене латинской буквы "R" на кириллическую "Р" и символизирует адаптацию программы под потребности пользователей "1С: Предприятия". Логотип R и логотип DataReducer Console распространяются на условиях лицензии CC-BY-SA 4.0.