R -> kdb: передать данные R в kdb+ как двоичные объекты

Какой самый эффективный способ вставить R объекты (более конкретно, временные ряды, выраженные как xts или же data.table объекты, то есть основанные на времени и числовые столбцы) в kdb+ база данных?

Мне удалось найти только решение, связанное с сериализацией строк через q выражения, как описано здесь и здесь.

2 ответа

Мое решение было вдохновлено этой версией qserver.c от github

Ян добавил две функции: convert_binary, convert_r, которые [де] сериализовали данные, что в основном и было то, что вы просили. Однако возвращаемое значение представляет собой шестнадцатеричный массив. Чтобы соединиться с существующей функцией execute, нам нужно использовать paste(collapse="") для преобразования в строку, а затем использовать sprintf для выполнения. Ниже приведен пример, который отправит robj в R в d в kdb:

execute(h, sprintf("d:-9!0x%s",paste(convert_r(robj),collapse="")))

Проблема в том, что paste(collapse="") занимает довольно много времени, если массив большой.

Robj - это объект r. Например, я попробовал это с data.frame (dim = 60,000x100). convert_r() потребовалось < 0.5s для конвертации; Для вставки (collapse = "") потребовалось 13 секунд, чтобы преобразовать в одну строку, а затем выполнить (h,...) для передачи данных - < 1.

Я не нашел никого, кто написал функцию, отправляющую R Data в kdb через сериализованные двоичные данные (я не знаю почему), поэтому я сделал ее сам. Вот код:

SEXP kx_r_send_data(SEXP connection, SEXP robj, SEXP varname)
{
  K result, conversion, serialized;
  kx_connection = INTEGER_VALUE(connection);
  conversion = from_any_robject(robj);
  serialized = b9(2, conversion);
  result = k(kx_connection, "{[d;v] v set -9!d;}", r1(serialized), ks((S)CHARACTER_VALUE(varname)), (K)0);
  SEXP s = from_any_kobject(result);
  r0(result);
  r0(conversion);
  r0(serialized);
  return s;
}

Я предполагаю, что у вас есть знания для изменения qserver.c и перекомпиляции qserver.o. Затем вы добавляете функцию в qserver.R:

send_data <- function(connection, r_obj, varname) {
  .Call("kx_r_send_data", as.integer(connection), r_obj, varname)
}

Это верный способ отправки данных R в kdb через сериализованный двоичный файл на уровне C.

Замечания:

1) преобразование не работает с data.table, поскольку это не стандартный класс R. Вызов функции с помощью data.table приведет к ошибке сегментации.

2) Сериализация не знает, как преобразовать тип даты / даты / времени. Сериализация сделает все это 0N после перевода в kdb.

Если вы не хотите реализовать преобразование date/datetime/data.table из R в K, НЕ вызывайте функции convert_r() или send_data() для этих типов.

С другой стороны, существует быстрый обходной путь. Для data.table просто используйте as.data.frame, чтобы преобразовать его в класс data.frame перед вызовом функций. Для класса date / datetime используйте as.character() для преобразования в строку перед отправкой в ​​kdb. Затем приведите к "D" или "P" внутри KDB напрямую.

3) сериализация data.frame включает в себя другую информацию, такую ​​как строки, имя строки, информация о классе и т. Д. Вам нужно манипулировать данными внутри kdb после передачи.

Я бы предложил написать функцию-обертку R, которая обрабатывает эти ненормальные случаи, а затем вызвать send_data() для передачи данных в kdb. Затем используйте execute(h, ...) для обработки данных в стандартном формате внутри kdb.

Те же данные (60 000x100) теперь требуют < 1 с, чтобы закончить, сквозной от R до kdb.

PS> У меня может быть опечатка внутри кода, так как я не знаю, как вставить сюда красивый код. Я фактически напечатал это вместо этого. Дайте мне знать, если вы нашли какую-либо критическую опечатку в коде

Самый "стабильный" способ взаимодействия с kdb из R - это использование интерфейса строковых запросов. Если вы хотите фактическую сериализацию объекта [de], предложите вам взглянуть на интерфейс C и вызвать этот lib из R для взаимодействия с KDB.

Другие вопросы по тегам