2016-05-04 3 views
1

Я пытаюсь передать довольно большой (65 ГБ) JSON-файл из дампа данных YASP (https://github.com/yasp-dota/yasp/wiki/JSON-Data-Dump), но кажется, что способ форматирования файла JSON означает, что я не могу прочитать файл, и выдает эту ошибку:Невозможно использовать jsonlite :: stream_in с определенными форматами 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 function ион

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="") 

В то время как это делает работу и создать строку символов, я могу читать в fromJSON, это не является масштабируемым решением для меня, так как я могу читать только несколько тысяч строк за раз, как это, и не очень масштабируемым (я также хотел бы иметь возможность передавать потоки непосредственно из gz-файла).

Кто-нибудь знает, как я могу получить stream_in, чтобы принять этот fileformat, или альтернативный способ сделать это с помощью R? Они показывают примеры того, как это работает на Java отлично, но я бы хотел, чтобы это удалось, не вскакивая на язык, который я действительно не знаю.

Update

До сих пор не получил поток работать, но писал мой собственный (своего рода), кажется, выполняют прилично для моих целей.

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

'jsonline :: stream_in' хочет, чтобы его данные были в формате' ndjson'. Этот формат, среди прочего, требует, чтобы каждая строка ввода была полной линией JSON, см. Http://ndjson.org/. Это объясняет, почему readlines + paste работает для вас. Может быть, вы можете поделиться внутренней структурой файла данных размером 65 Гб? – Dinesh

+0

Dinesh: Структура файла описана в ссылке выше (https://github.com/yasp-dota/yasp/wiki/JSON-Data-Dump), она показывает, как одна строка JSON находится в файле, и файл содержит 500 000 строк JSON. Затем есть оболочка [] вокруг всех этих 500 000 строк, и запятая между каждой строкой. Оба скобки [] (по одному для каждой, первая и последняя строка файла 65 ГБ) и каждая запятая имеют собственную строку, что, по-видимому, вызывает проблему. –

+0

, если весь файл является одним единственным объектом, тогда вы, вероятно, вернетесь к той же проблеме синтаксического разбора. Я изменил ваш источник на 3 независимых объекта (без разделительных запятых) в 3-х строках и импортировал - он завершил, как ожидалось, и без ошибки. Не знаете, как это поможет, но хотели поделиться: - | – Dinesh

ответ

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 была.

Смежные вопросы