来自RODBC的sqlQuery上的parlapply

时间:2014-07-02 22:05:57

标签: r parallel-processing rodbc

R版本:2.14.1 x64 在Windows 7上运行 连接到远程Microsoft SQL Server 2012上的数据库

我有一个无序的名字向量,说:

names<-c(“A”, “B”, “A”, “C”,”C”)

每个都在我的数据库中的表中有一个id。我需要将名称转换为相应的ID。

我目前有以下代码来执行此操作。

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects

nameToID<-function(name, dbConn){
                #dbConn : active db connection formed via odbcDriverConnect
                #name     : a char string

                sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))
}
sapply(names, nameToID, dbConn=dbConn)
###

除非有更好的方法来执行此操作,这可能涉及将表加载到R然后处理问题(这是可能的),我理解为什么以下不起作用,但我似乎无法找到解决方案。尝试通过“并行”包使用并行化:

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects

nameToID<-function(name, dbConn){
                #dbConn : active db connection formed via odbcDriverConnect
                #name     : a char string

                sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))
}

mc<-detectCores()
cl<-makeCluster(mc)
clusterExport(cl, c(“sqlQuery”, “dbConn”))
parSapply(cl, names, nameToID, dbConn=dbConn)    #incorrect passing of nameToID’s second argument
###

与评论一样,这不是将第二个参数分配给nameToID的正确方法。

我也尝试了以下内容:

parSapply(cl, names, function(x) nameToID(x, dbConn))

代替之前的parSapply调用,但这也不起作用,抛出错误说“第一个参数不是一个开放的RODBC连接”,可能是指sqlQuery()的第一个参数。 dbConn仍然打开

以下代码适用于并行化。

###
names<-c(“A”, “B”, “A”, “C”,”C”)
dbConn<-odbcDriverConnect(connection=”connection string”) #successfully connects
nameToID<-function(name){
                #name     : a char string
                dbConn<-odbcDriverConnect(connection=”string”)
                result<-sqlQuery(dbConn, paste(“select id from table where name=’”, name, “’”, sep=””))
                odbcClose(dbConn)
                result
}

mc<-detectCores()
cl<-makeCluster(mc)
clusterExport(cl, c(“sqlQuery”, “odbcDriverConnect”, “odbcClose”, “dbConn”, “nameToID”))      #throwing everything in
parSapply(cl, names, nameToID)
###

但是连接的不断打开和关闭破坏了并行化带来的好处,而且看起来有点傻。

所以整体问题是如何将第二个参数(开放数据库连接)传递给parSapply中的函数,其方式与常规应用中的方式大致相同?一般来说,如何将第二个,第三个,第n个参数传递给并行例程中的函数?

谢谢,如果您需要更多信息,请告诉我们。

-DT

1 个答案:

答案 0 :(得分:2)

数据库连接对象无法作为函数参数导出或传递,因为它们包含套接字连接。如果您尝试,它将被序列化,发送给工作人员并反序列化,但由于套接字连接无效,因此无法正常工作。

解决方案是在调用parSapply之前在每个worker上创建数据库连接。我经常使用clusterEvalQ:

clusterEvalQ(cl, {
    library(RODBC)
    dbConn <- odbcDriverConnect(connection="connection string")
    NULL
})

现在,worker函数可以写成:

nameToID <- function(name) {
    sqlQuery(dbConn, paste("select id from table where name='", name, "'", sep=""))
}

并致电:

parSapply(cl, names, nameToID)  

另请注意,由于每个工作人员都加载了RODBC,因此您不必导出其中定义的函数,我认为这是一种很好的编程习惯。