【发布时间】:2014-12-27 22:42:57
【问题描述】:
将R 对象(更具体地说,时间序列表示为xts 或data.table 对象,即基于时间的列和数字列)插入kdb+ 数据库的最有效方法是什么?
【问题讨论】:
将R 对象(更具体地说,时间序列表示为xts 或data.table 对象,即基于时间的列和数字列)插入kdb+ 数据库的最有效方法是什么?
【问题讨论】:
我的解决方案受到了这个版本的启发 qserver.c from github
Yang 增加了两个函数:convert_binary,convert_r 对数据进行[反]序列化,基本上就是你想要的。但是,返回值是一个十六进制数组。要与现有的执行功能结合,我们需要使用 paste(collapse="") 转换成字符串,然后使用 sprintf 执行。下面是例子,它将R中的robj发送到kdb中的d:
execute(h, sprintf("d:-9!0x%s",paste(convert_r(robj),collapse="")))
问题是如果数组很大,paste(collapse="") 需要相当长的时间。
robj 是 r 对象。例如我用 data.frame (dim = 60,000x100) 尝试了它。 convert_r() 转换耗时 paste(collapse="") 用了 13s 转换成一个字符串,然后 execute(h, ...) 用了
我还没有找到任何人编写了通过序列化二进制数据将 R 数据发送到 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)
}
这才是在 C 级别通过序列化二进制将 R 数据发送到 kdb 的真正方式。
注意:
1) 转换不适用于 data.table,因为它不是标准的 R 类。用data.table调用函数会导致segmentation fault。
2) 序列化不知道如何转换 date/datetime 类型的对象。转入kdb后,序列化会使其全部0N。
除非你想实现从 R 到 K 的 date/datetime/data.table 转换,不要调用 convert_r() 或 send_data() 这些类型的函数。
另一方面,有一个快速的解决方法。对于data.table,只需在调用函数之前使用as.data.frame 将其转换为data.frame 类。 对于日期/日期时间类,使用 as.character() 在发送到 kdb 之前转换为字符串。然后直接在 KDB 中转换为“D”或“P”。
3) 序列化的data.frame中包含了行、行名、类信息等其他信息,需要在传输后对kdb内部的数据进行操作。
我建议编写一个 R 包装函数来处理这些异常情况,然后调用 send_data() 将数据传递给 kdb。然后使用 execute(h, ...) 将数据操作成 kdb 内部的标准格式。
相同的数据 (60,000x100) 现在需要
PS> 我可能在代码中有错字,因为我不知道如何在此处粘贴漂亮的代码。我实际上是把它打出来的。如果您在代码中发现任何严重的拼写错误,请告诉我
【讨论】:
与 R 中的 kdb 交互最“稳定”的方式是使用字符串查询接口。如果您想要实际的对象 [反] 序列化,那么建议您查看 C 接口并从 R 调用该库以与 KDB 交互。
【讨论】: