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.