【问题标题】:R: Memory Management during xmlEventParse of Huge (>20GB) filesR:大型(> 20GB)文件的xmlEventParse期间的内存管理
【发布时间】:2018-04-20 03:29:59
【问题描述】:

基于上一个问题 (see here),我尝试通过 xmlEventParse 读取许多大型 xml 文件,同时保存节点变化的数据。使用此示例 xml:https://www.nlm.nih.gov/databases/dtd/medsamp2015.xml

下面的代码使用 xpathSapply 提取必要的值和一系列 if 语句以将唯一值 (PMID) 与记录中的每个非唯一值 (LastName) 匹配的方式组合值 - 对于其中可能没有姓氏。目标是沿途编写一系列小的 csv(这里,在每 1000 个姓之后),以尽量减少使用的内存量。

在全尺寸数据集上运行时,代码成功地批量输出文件,但是内存中仍存储一些内容,一旦使用所有 RAM,最终会导致系统错误。我在代码运行时观察了任务管理器,并且可以看到 R 的内存随着程序的进行而增长。如果我在运行过程中停止程序然后清除 R 工作区,包括隐藏的项目,内存似乎仍在被 R 使用。直到我关闭 R 才再次释放内存。

自己运行几次,你会看到 R 的内存使用量即使在清除工作区后也会增长。

请帮忙!这个问题对于以这种方式读取大型 XML 文件的其他人来说似乎很常见(参见例如 cmets in this question)。

我的代码如下:

library(XML)

filename <- "~/Desktop/medsamp2015.xml"

tempdat <- data.frame(pmid=as.numeric(),
                      lname=character(), 
                      stringsAsFactors=FALSE) 
cnt <- 1
branchFunction <- function() {
  func <- function(x, ...) {
    v1 <- xpathSApply(x, path = "//PMID", xmlValue)
    v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
    print(cbind(c(rep(v1,length(v2))), v2))

    #below is where I store/write the temp data along the way
    #but even without doing this, memory is used (even after clearing)

    tempdat <<- rbind(tempdat,cbind(c(rep(v1,length(v2))), v2))
    if (nrow(tempdat) > 1000){
      outname <- paste0("~/Desktop/outfiles",cnt,".csv")
      write.csv(tempdat, outname , row.names = F)
      tempdat <<- data.frame(pmid=as.numeric(),
                            lname=character(), 
                            stringsAsFactors=FALSE)
      cnt <<- cnt+1
    }
  }
  list(MedlineCitation = func)
}

myfunctions <- branchFunction()

#RUN
xmlEventParse(
  file = filename, 
  handlers = NULL, 
  branches = myfunctions
)

【问题讨论】:

  • 刚刚更新了代码,下载后应该可以运行:nlm.nih.gov/databases/dtd/medsamp2015.xml。内存问题仍然存在。
  • 你在什么操作系统上运行? Windows、L*nux、Mac OSX?
  • 也许你会使用类似 tempdat[i]
  • @Technophobe01 无论我是在 Windows 还是 Mac 上,我都会遇到这个问题,这让我认为这与 xmlEventParse 在内存中存储的东西有关,这些东西在没有 R 关闭的情况下是隐藏且不可擦除的
  • @km5041 您正在使用的库可能是用 c 或 c++ 编写的,它正在分配 R 会话控制之外的内存。因此,内存泄漏在 R 会话之外但会影响它。我解决这类问题的方法是跨 RScript 实例划分分析。打破工作。见:stackoverflow.com/questions/37264919/…

标签: r xml memory-management xml-parsing large-files


【解决方案1】:

这是一个例子,我们有一个启动脚本invoke.sh,它调用一个R脚本并将url和文件名作为参数传递......在这种情况下,我之前已经下载了测试文件medsamp2015.xml并放入./data 目录。

  • 我的感觉是在invoke.sh 脚本中创建一个循环并遍历目标文件名列表。对于调用 R 实例的每个文件,下载它、处理文件并继续下一个。

警告:我没有针对任何其他下载文件和格式检查或更改您的功能。我将通过删除第 62 行的 print() 包装器来关闭输出的打印。

print( cbind(c(rep(v1, length(v2))), v2))
  • 请参阅:runtime.txt 打印输出。
  • 输出的.csv文件放在./data目录下。

注意:这是我在此主题上提供的先前答案的派生词: R memory not released in Windows。我希望它以举例的方式有所帮助。

启动脚本

  1 #!/usr/local/bin/bash -x
  2
  3 R --no-save -q --slave < ./47162861.R --args "https://www.nlm.nih.gov/databases/dtd" "medsamp2015.xml"

R 文件 - 47162861.R

# Set working directory

projectDir <- "~/dev/stackoverflow/47162861"
setwd(projectDir)

# -----------------------------------------------------------------------------
# Load required Packages...
requiredPackages <- c("XML")

ipak <- function(pkg) {
  new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
  if (length(new.pkg))
    install.packages(new.pkg, dependencies = TRUE)
  sapply(pkg, require, character.only = TRUE)
}

ipak(requiredPackages)

# -----------------------------------------------------------------------------
# Load required Files
# trailingOnly=TRUE means that only your arguments are returned
args <- commandArgs(trailingOnly = TRUE)

if ( length(args) != 0 ) {
  dataDir <- file.path(projectDir,"data")
  fileUrl = args[1]
  fileName = args[2]
} else {
  dataDir <- file.path(projectDir,"data")
  fileUrl <- "https://www.nlm.nih.gov/databases/dtd"
  fileName <- "medsamp2015.xml"
}

# -----------------------------------------------------------------------------
# Download file

# Does the directory Exist? If it does'nt create it
if (!file.exists(dataDir)) {
  dir.create(dataDir)
}

# Now we check if we have downloaded the data already if not we download it

if (!file.exists(file.path(dataDir, fileName))) {
  download.file(fileUrl, file.path(dataDir, fileName), method = "wget")
}

# -----------------------------------------------------------------------------
# Now we extrat the data

tempdat <- data.frame(pmid = as.numeric(), lname = character(),
  stringsAsFactors = FALSE)
cnt <- 1

branchFunction <- function() {
  func <- function(x, ...) {
    v1 <- xpathSApply(x, path = "//PMID", xmlValue)
    v2 <- xpathSApply(x, path = "//Author/LastName", xmlValue)
    print(cbind(c(rep(v1, length(v2))), v2))

    # below is where I store/write the temp data along the way
    # but even without doing this, memory is used (even after
    # clearing)

    tempdat <<- rbind(tempdat, cbind(c(rep(v1, length(v2))),
      v2))
    if (nrow(tempdat) > 1000) {
      outname <- file.path(dataDir, paste0(cnt, ".csv")) # Create FileName
      write.csv(tempdat, outname, row.names = F) # Write File to created directory
      tempdat <<- data.frame(pmid = as.numeric(), lname = character(),
        stringsAsFactors = FALSE)
      cnt <<- cnt + 1
    }
  }
  list(MedlineCitation = func)
}

myfunctions <- branchFunction()

# -----------------------------------------------------------------------------
# RUN
xmlEventParse(file = file.path(dataDir, fileName),
              handlers = NULL,
              branches = myfunctions)

测试文件和输出

~/dev/stackoverflow/47162861/data/medsamp2015.xml

$ ll                                                            
total 2128
drwxr-xr-x@ 7 hidden  staff   238B Nov 10 11:05 .
drwxr-xr-x@ 9 hidden  staff   306B Nov 10 11:11 ..
-rw-r--r--@ 1 hidden  staff    32K Nov 10 11:12 1.csv
-rw-r--r--@ 1 hidden  staff    20K Nov 10 11:12 2.csv
-rw-r--r--@ 1 hidden  staff    23K Nov 10 11:12 3.csv
-rw-r--r--@ 1 hidden  staff    37K Nov 10 11:12 4.csv
-rw-r--r--@ 1 hidden  staff   942K Nov 10 11:05 medsamp2015.xml

运行时输出

> ./invoke.sh > runtime.txt
+ R --no-save -q --slave --args https://www.nlm.nih.gov/databases/dtd medsamp2015.xml
Loading required package: XML

文件:runtime.txt

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 2011-05-02
    • 2011-06-14
    • 2014-05-27
    • 2018-05-04
    • 1970-01-01
    相关资源
    最近更新 更多