{ 中的 FOREACH 循环错误:任务 1 失败 - "could not find function "dbGetQuery""

FOREACH LOOP Error in { : task 1 failed - "could not find function "dbGetQuery""

我在 R 中的简单实现方面经验丰富,但是我不熟悉通过 R 与 SQL 通信以及并行编程(在今天之前没有这两件事的经验)。我根据博客、论坛等的提示编写了以下代码。

library(doParallel) 

library(RMySQL) 

library(DBI)

library(foreach)

cl <- makeCluster(12)

registerDoParallel(cl)

Postcodecsv <- read.csv("C:/Users/Henry Crosby/Desktop/PostcodeLatLong.csv")

mydb = dbConnect(MySQL(), user='****', password="******* ****", 

dbname='population_distance', host='****.**.*.*')

dbListFields(mydb,'Postcodes')

foreach (a = 1:120000, .combine="rbind") %dopar% {

  Done <- dbGetQuery(mydb, paste("select FID, Postcode2, (6371 * acos( cos( 
radians( ",Postcodecsv[a,6],"))*cos(radians(latitude))*cos(radians(Longitude)-radians(",Postcodecsv[a,5],"))+sin(radians(",Postcodecsv[a,6],") )* sin( radians( latitude ) ) ) ) AS distance from Postcodes having distance < 2 ORDER BY distance",sep=" "))

write.table(Done,file="C:/Users/Henry Crosby/Desktop/2km.csv",append=TRUE, col.names=FALSE, sep=",")

  } 

此计算在 for 循环中进行但需要很长时间(我必须将其应用于大型数据集!)。当我 运行 以上代码时,出现以下错误!谁能告诉我为什么会出现错误以及我该如何解决它!

Error in { : task 1 failed - "could not find function "dbGetQuery""

问题是 foreach 是 auto-exporting mydb 对象,但它无法正常工作,因为包含套接字连接的对象无法在进程之间序列化和复制。

我建议您使用 clusterEvalQ 函数初始化集群 worker,以便在每个 worker 上创建 mydb。你可以尝试这样的事情:

clusterEvalQ(cl, {
  library(RMySQL)
  mydb <- dbConnect(MySQL(), user='****', password="******* ****",
                    dbname='population_distance', host='****.**.*.*')
  NULL
})

但是,您仍然需要使用 foreach .noexport="mydb" 选项来阻止 foreach auto-exporting mydb。您还可以使用 foreach .verbose=TRUE 选项来验证哪些对象正在 auto-exported 工作人员。

为什么要使用 R 处理 sql 到 csv 的迁移?考虑一个完整的 SQL 解决方案并将处理留在数据库引擎上。具体就是加入Postcodestable和PostcodeLatLong csv数据(当然是导入到MySQL数据库)。然后使用 MySQL 的 OUTFILE 工具。总而言之,您只需 运行 dbGetQuery() 一次,无需并行循环:

expotCSV <- dbGetQuery("SELECT FID, Postcode2, (6371 * acos( cos( 
                     radians(Postcodecsv.col6))*cos(radians(latitude))*cos(radians(Longitude)-
                     radians(Postcodecsv.col5))+sin(radians(Postcodecsv.col6))* sin(radians(latitude)))) 
                     AS distance     

              FROM Postcodes 
              INNER JOIN PostcodeLatLong ON csv.joinfield = PostcodeLatLong.joinfield
              HAVING distance < 2 
              ORDER BY distance

              INTO OUTFILE 'C:/Users/Henry Crosby/Desktop/2km.csv' 
              FIELDS ENCLOSED BY '\"' 
              TERMINATED BY ';' 
              ESCAPED BY '\"' 
              LINES TERMINATED BY '\r\n';")

挑战在于找到 joinfield 或两个 table 之间的关系。但是,SQL 还允许 cartesian product or the cross join(对于看似无关的 tables),其中查询 returns 列出的 tables 之间的总组合集。您可以通过某些过滤子句使用 where 子句:

FROM Postcodes, PostcodeLatLong 
WHERE Postcodes.somefactor = "..." AND PostcodeLatLong.somefactor = "..."

或者,MySQL 的 CROSS JOIN(没有 ON 子句的 JOIN)

FROM Postcodes CROSS JOIN PostcodeLatLong 
WHERE Postcodes.somefactor = "..." AND PostcodeLatLong.somefactor = "..."