Массовая обработка#

Описание раздела#

Скрипты и шаблоны для обработки больших объёмов данных в JEXL. Используются при миграции, пересчёте, восстановлении или массовом обновлении записей. Содержат примеры работы с ElExpOQuery, Btk_BulkProcessPkg и передачи Scala-объектов через MODULE$.

Скрипты#

Шаблон массовой обработки через ElExpOQuery#

Используется как основа для написания производительных JEXL-скриптов, обрабатывающих тысячи записей. Демонстрирует использование объектного запроса ElExpOQuery для пакетной загрузки сущностей и обработки по чанкам.

Место применения: Сервис > Инструменты > Выполнить JEXL-скрипт

Внимание

Требует адаптации под конкретную сущность и версию системы. Перед использованием убедитесь, что целевой API (например, Co_ProdCostDocEntryApi) и соответствующие Scala-объекты доступны в вашей версии платформы.

Тип: JEXL-скрипт

const vDocApi = Co_ProdCostDocEntryApi;

const mkDocOQuery = (idap) => {
  const vOQ = new ru.bitec.app.gtk.eclipse.query.ElExpOQuery(vDocApi);
  const idavAL = new java.util.ArrayList();
  idap.foreach(idv => idavAL.add(idv));

  vOQ.forWhere(vBuilder => vBuilder.get("id").in(idavAL.toArray()) );
  vOQ.batchIn(
    asScala([session.sbtClassLoader().loadClass("ru.bitec.app.co.prodcostdocentry.Co_ProdCostDocEntryDetAta$").MODULE$, ...])
  );
  return vOQ;
};

asScala(sql(`
  select t.id
    from Co_ProdCostDocEntry t
   where t.dDoc is not null
     and t.idStateMC >= 300
`).asList()).grouped(400).foreach(ravBatch => {
  mkDocOQuery(ravBatch.map(r => r.id)).foreach(ropDoc => {
    Co_ProdCostRegFullApi.createItemsByDoc(ropDoc, ropDoc.dDoc);
  });
  commit();
});

Шаблон массовой обработки через Btk_BulkProcessPkg#

Используется как основа для массовой обработки записей с автоматическим разбиением на чанки. Демонстрирует применение Btk_BulkProcessPkg.chunkedQuery для безопасной работы с большими выборками без переполнения памяти.

Место применения: Сервис > Инструменты > Выполнить JEXL-скрипт

Внимание

Требует адаптации под конкретную сущность и версию системы. Классы Scala-объектов (например, Co_ProdCostDocEntryDetAta$) могут отсутствовать или измениться в новых версиях платформы.

Тип: JEXL-скрипт

Btk_BulkProcessPkg.chunkedQuery(
  Co_ProdCostDocEntryApi,
  5000L,
  `select t.id from Co_ProdCostDocEntry t`,
  asScala([...]), // Неизвестен способ передачи NamedParameter из JEXL
  asScala([session.sbtClassLoader().loadClass("ru.bitec.app.co.prodcostdocentry.Co_ProdCostDocEntryDetAta$").MODULE$, ...]),
  false,
  false,
  ropa => {
    ropa.foreach(rop => Btk_InfoLogPkg.info(rop.gid));
  }
);

Обработка данных пакетами#

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

Скрипт показывает подход для массового изменения большого объема данных, когда обработка всех записей за один проход может привести к переполнению памяти и остановке веб-приложения. Записи выбираются и обрабатываются пачками. После обработки каждой пачки выполняется commit(), затем запрашивается следующая часть данных.

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

Место применения: Сервис > Инструменты > Выполнить JEXL-скрипт

Тип: JEXL-скрипт

// Обработка данных по пачкам
var batchSize = 200;
var nCount = 0;
var nOffset = 0;

var sqlText = `
<запрос>
`;

while (true) {
  // offset не нужен, если после каждой пачки отдается commit в БД
  // и запрос исключает уже обработанные записи
  var listSQL = sql(sqlText + " offset " + nOffset + " limit " + batchSize).asList();
  
  // Условие выхода из цикла
  if (listSQL.isEmpty()) {
    break;
  }
  
  for (data : listSQL) {
    var ropPlacement = Bs_PlacementApi.load(data.id);
    Bs_PlacementApi.setObjAttrValue(ropPlacement, "idMonitorTrainLocationType", data.idtype);
    nCount += 1;
  }
  
  commit();
  nOffset += batchSize;
}

// Результат
if (nCount == 0) {
  dialogs.showMessage("Исправлять нечего.");
} else {
  dialogs.showMessage("Исправлено " + nCount + " записей.");
}