R: управление памятью во время xmlEventParse огромных (>20 ГБ) файлов
Основываясь на этом предыдущем вопросе (смотрите здесь ), я пытаюсь читать во многих больших xml-файлах с помощью xmlEventParse, сохраняя изменяющиеся по узлам данные. Работа с этим примером xml: https://www.nlm.nih.gov/databases/dtd/medsamp2015.xml .
Приведенный ниже код использует xpathSapply для извлечения необходимых значений и ряд операторов if для объединения значений таким образом, чтобы уникальное значение (PMID) соответствовало каждому из неуникальных значений (фамилия) в записи - для которых не может быть никаких фамилий. Цель состоит в том, чтобы написать серию небольших csv по пути (здесь, после каждых 1000 фамилий), чтобы минимизировать объем используемой памяти.
При запуске на полноразмерном наборе данных, код успешно выводит файлы в пакетах, однако что-то все еще хранится в памяти, что в конечном итоге вызывает системную ошибку, как только вся оперативная память используется. Я наблюдал за диспетчером задач во время выполнения кода и могу видеть, как память R растет по мере выполнения программы. И если я остановлю ... программа в середине выполнения, а затем очистить рабочее пространство R, включая скрытые элементы, память по-прежнему, кажется, используется R. это не так, пока я выключаю R память освобождается снова.
Запустите это несколько раз самостоятельно, и вы увидите, что использование памяти R растет даже после очистки рабочей области.
Пожалуйста, помогите! Эта проблема, по-видимому, является общей для других, читающих в больших XML-файлах таким образом (см., например, комментарии в этом вопросе).
Мой код выглядит следующим образом: образом:
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
)
1 ответ:
Вот пример, у нас есть скрипт запуска
invoke.sh
, который вызывает скрипт R и передает url и имя файла в качестве параметров... В этом случае я предварительно скачал тестовый файл medsamp2015.xml и поместить в каталог./data
.
- мой смысл состоял бы в том, чтобы создать цикл в скрипте
invoke.sh
и перебрать список имен целевых файлов. Для каждого файла вы вызываете экземпляр R, загружаете его, обрабатываете файл и переходите к следующему.Предостережение: I не проверял и не изменял свою функцию по сравнению с другими загружаемыми файлами и форматами. Я бы выключил печать вывода, удалив обертку print() в строке 62.
print( cbind(c(rep(v1, length(v2))), v2))
- см.: среда выполнения.txt для распечатки.
- выходные файлы
.csv
помещаются в каталог./data
.Примечание: это производная от предыдущего ответа, предоставленного мной по этому вопросу.: R память, не освобожденная в 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
Файл: среда выполнения.txt