通过R将大型数据框存储在Redis中

6

我在R中有许多大型数据框,计划使用redis进行存储。我对redis完全不熟悉,但今天一直在阅读相关知识,并使用了R软件包rredis

我已经尝试使用redisSet()redisGet()函数保存和检索小数据框,但是当我尝试使用redisSet('bigDF', bigDF)保存较大的数据框(最大的一个有430万行,以.RData文件格式保存时大小为365MB)时,出现以下错误信息:

Error in doTryCatch(return(expr), name, parentenv, handler) : 
  ERR Protocol error: invalid bulk length
In addition: Warning messages:
1: In writeBin(v, con) : problem writing to connection
2: In writeBin(.raw("\r\n"), con) : problem writing to connection

可能是因为数据框太大而无法保存。我知道redisSet将数据框写为字符串,这可能不是处理大型数据框的最佳方式。请问有人知道最佳方法是什么吗?

编辑:我通过创建一个非常大的虚拟数据框重新创建了错误:

bigDF <- data.frame(
'lots' = rep('lots',40000000),
'of' = rep('of',40000000),
'data' = rep('data',40000000),
'here'=rep('here',40000000)
)

执行redisSet('bigDF',bigDF)时出现错误:

 Error in .redisError("Invalid agrument") : Invalid agrument

第一次执行后,紧接着再次运行,就会出现错误。
Error in doTryCatch(return(expr), name, parentenv, handler) : 
  ERR Protocol error: invalid bulk length
In addition: Warning messages:
1: In writeBin(v, con) : problem writing to connection
2: In writeBin(.raw("\r\n"), con) : problem writing to connection

谢谢


请在格式化的代码块中分享您正在使用的实际代码。这将使有经验的人更容易诊断并建议调整。 - Simon O'Hanlon
1个回答

7

简而言之:不行。 Redis可以在字符串值中存储最多512MB的数据,而您的序列化演示数据框大于此大小:

> length(serialize(bigDF, connection = NULL)) / 1024 / 1024
[1] 610.352

技术背景:

serialize 函数通过 redisSetrredis:::.redisCmd 在包的 .cerealize 函数中被调用:

> rredis:::.cerealize
function (value) 
{
    if (!is.raw(value)) 
        serialize(value, ascii = FALSE, connection = NULL)
    else value
}
<environment: namespace:rredis>

话题偏离:你为什么要将这么大的数据集存储在Redis中呢?Redis适用于小型键值对。另一方面,我曾经尝试将大型R数据集存储在CouchDBMongoDB(使用GridFS)中,通过将压缩的RData作为附件添加。


谢谢daroczig,所以您的查询长度(序列化(...会返回字符串值在Mb中的大小?我想我可以将数据框分为两部分并分别保存它们,但考虑到您的最终评论,我认为您不建议这样做?关于您的问题,我刚开始使用redis,所以不知道它存储大型数据集的限制,我听说它是快速存储和检索数据的好方法,所以只是看了一下。我也会研究CouchDB和MongoDB。 - user1165199
1
你的R数据集的最佳存储方式取决于你的需求。redis当然非常快,因为它应该将所有内容存储在内存中,所以你应该只在物理内存允许的范围内存储尽可能多的数据。另一方面,如果你只在本地主机上访问这些数据,那么就不需要DB后端:创建一个RAM磁盘并在其中快速写入RData,随时重新加载即可。你还应该找出最佳的压缩方法和比率(CPU vs IO)。如果你使用多台计算机,则根据你的需求选择DB,如复制、分片等。 - daroczig
1
@daroczig,您上面的帖子忽略了其他需要将更大的项目存储在Redis中的原因,关键词:数据交换。有人可能会在C#中生成较大的数据项,并将其存储在Redis中,以便轻松访问R或者反过来。当源数据和目标数据之间的位置不共享且Redis是唯一的交换点时,使用Redis进行数据交换非常有意义。当然,如果只想在R中生成数据并稍后重新访问,则将其存储到磁盘中是最佳解决方案,可能与内存映射文件相结合。 - Matt
1
@daroczig,我不同意,只举两个例子:a)一个不断变化的数据集(通过追加或覆盖)。 通过文件I / O维护这样的数据集将非常麻烦。 最好只需使用Redis中已知键的值进行更新,此外您还可以发布更新通知,任何具有Redis访问权限的人都可以使用它。 b)除非您达到Redis或物理内存的限制,否则没有理由必须通过文件进行操作。 如果数据太大,则可以轻松地将其分成几部分,430万行根本不算什么。 - Matt
我们生活在分布式计算的时代,文件I/O会将您锁定在同一台物理机器上的操作中,除非您想编写一个文件I/O服务器和客户端。Redis可以分布在任何地方,我目前将其用于进程间通信以及非持久化项目的键/值存储(尽管它可以持久化)。因此,如果提问者只想在同一台机器上写入和读取相同的数据,则应优先选择文件I/O,但对于其他情况,应优先选择共享数据库,其中包括Redis。 - Matt
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接