我正在尝试从YASP数据转储(https://github.com/yasp-dota/yasp/wiki/JSON-Data-Dump)流式传输相当大的(65gb)JSON文件,但似乎JSON文件的格式化方式意味着我无法读取该文件,并且给出了这个错误:
错误:解析错误:过早的EOF [ (就在这里)------ ^
我使用相同的格式创建了这个小样本JSON文件,以便其他人可以轻松地重新创建它:
[
{"match_id": 2000594819,"match_seq_num": 1764515493}
,
{"match_id": 2000594820,"match_seq_num": 1764515494}
,
{"match_id": 2000594821,"match_seq_num": 1764515495}
]
我已将此文件保存为test.json,并尝试通过jsonlite :: stream_in函数加载它
library(jsonlite)
con <- file('~/yasp/test.json')
jsonStream <- stream_in(con)
我得到了相同的“过早EOF”错误,如上所示。
但是,如果文件的格式全部在一个块中,如下所示:
[{"match_id": 2000594819,"match_seq_num": 1764515493},{"match_id": 2000594820,"match_seq_num": 1764515494},{"match_id": 2000594821,"match_seq_num": 1764515495}]
然后没有问题,stream_in工作正常。
我玩过readLines,并在阅读之前折叠框架:
initialJSON <- readLines('~/yasp/test.json')
collapsedJSON <- paste(initialJSON, collapse="")
虽然这确实有效并且创建了一个我可以从JSON读取的字符串,但这对我来说不是一个可扩展的解决方案,因为我一次只能读取几千行,并且不是很可扩展(i 'd也喜欢能够直接从gz文件中流式传输)。
有谁知道我怎么能让stream_in接受这个文件格式,或者用R做一些替代方法?他们展示了它如何在Java中运行良好的例子,但我希望能够做到这一点,而不会跳到我不知道的语言。
仍然没有得到流工作,但写了我自己的(各种),似乎为我的目的正常表现。
fileCon <- file('~/yasp/test.json', open="r")
# Initialize everything
numMatches <- 5
outputFile <- 0
lineCount <- 0
matchCount <- 0
matchIDList <- NULL
# Stream using readLines and only look at even numbered lines
while(matchCount <= numMatches) {
next_line = readLines(fileCon, n = 1)
lineCount <- lineCount + 1
if(lineCount %% 2 == 0) {
matchCount <- matchCount + 1
# read into JSON format
readJSON <- jsonlite::fromJSON(next_line)
# Up the match counter
matchCount <- matchCount + 1
# whatever operations you want, for example get match_id
matchIDList <- c(matchIDList, readJSON$match_id)
}
}
答案 0 :(得分:0)
嗯,我从来没有让stream_in函数为我工作,但我创建了自己的流光,效果很好,占用空间很小。
streamJSON <- function(con, pagesize, numMatches){
library(jsonlite)
library(data.table)
library(plyr)
library(dplyr)
library(tidyr)
## "con" is the file connection
## "pagesize" is number of lines streamed for each iteration.
## "numMatches" is number of games we want to output
outputFile <- 0
matchCount <- 0
print("Starting parsing games...")
print(paste("Number of games parsed:",matchCount))
# Stream in using readLines until we reach the number of matches we want.
while(matchCount < numMatches) {
initialJSON = readLines(con, n = pagesize)
collapsedJSON <- paste(initialJSON[2:pagesize], collapse="")
fixedJSON <- sprintf("[%s]", collapsedJSON, collapse=",")
readJSON <- jsonlite::fromJSON(fixedJSON)
finalList <- 0
## Run throught he initial file
for (i in 1:length(readJSON$match_id)) {
## Some work with the JSON to return whatever it is i wanted to return
## In this example match_id, who won, and the duration.
matchList <- as.data.frame(cbind(readJSON$match_id[[i]],
readJSON$radiant_win[[i]],
readJSON$duration[[i]]))
colnames(matchList) <- c("match_id", "radiant_win", "duration")
## Assign to output
if (length(finalList) == 1) {
finalList <- matchList
} else {
finalList <- rbind.fill(finalList, matchList)
}
}
matchCount <- matchCount + length(unique(finalList[,1]))
if (length(outputFile) == 1) {
outputFile <- finalList
} else {
outputFile <- rbind.fill(outputFile, finalList)
}
print(paste("Number of games parsed:",matchCount))
}
return(outputFile)
}
不确定这对其他人是否有帮助,因为它可能对YASP数据转储有点特殊,但我现在可以像这样调用这个函数:
fileCon <- gzfile('~/yasp/yasp-dump-2015-12-18.json.gz', open="rb")
streamJSONPos(fileCon, 100, 500)
将使用指定的数据输出500行的数据帧,然后我必须修改while循环中的部分,无论我想要从JSON数据中提取它。
我已经能够在50.000次匹配(具有相当复杂的JSON功能)中流式传输,非常容易,并且似乎在与stream_in函数相同的时间(每次匹配)运行。