无法将 jsonlite::stream_in 用于某些 JSON 格式
Unable to use jsonlite::stream_in with certain JSON formats
我正在尝试从 YASP 数据转储 (https://github.com/yasp-dota/yasp/wiki/JSON-Data-Dump) 流式传输相当大的 (65gb) JSON 文件,但似乎 JSON 文件的方式是格式化意味着我无法读取文件,并给出此错误:
Error: parse error: premature EOF
[
(right here) ------^
我使用相同的格式创建了这个小示例 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)
我得到与上图相同的 "premature 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 读取的字符串,但这对我来说不是一个可扩展的解决方案,因为我一次只能读取几千行,并且可扩展性不是很好(我也希望能够直接从 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)
}
}
好吧,我从来没有使用过 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 函数是。
我正在尝试从 YASP 数据转储 (https://github.com/yasp-dota/yasp/wiki/JSON-Data-Dump) 流式传输相当大的 (65gb) JSON 文件,但似乎 JSON 文件的方式是格式化意味着我无法读取文件,并给出此错误:
Error: parse error: premature EOF [ (right here) ------^
我使用相同的格式创建了这个小示例 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)
我得到与上图相同的 "premature 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 读取的字符串,但这对我来说不是一个可扩展的解决方案,因为我一次只能读取几千行,并且可扩展性不是很好(我也希望能够直接从 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)
}
}
好吧,我从来没有使用过 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 函数是。