Как разобрать ndjson в Pharo с помощью NeoJSON

Я хочу проанализировать данные ndjson (json с разделителями новой строки) с NeoJSON на Pharo Smalltalk.

Данные ndjson выглядят так:

{"smalltalk": "cool"}
{"pharo": "cooler"}

В данный момент я конвертирую свой файловый поток в строку, разделяю ее на новую строку, а затем анализирую отдельные части с помощью NeoJSON. Кажется, что это использует ненужный (и чрезвычайно большой) объем памяти и времени, вероятно, из-за постоянного преобразования потоков в строки и наоборот. Каков был бы эффективный способ выполнить эту задачу?

Если вы ищете пример данных: NYPL-publicdomain: pd_items_1.ndjson

3 ответа

Решение

Это ответ Свена (автора NeoJSON) в списке рассылки pharo-users (он не на SO):

Читать "формат" легко, просто продолжайте делать #next для каждого выражения JSON (пробелы игнорируются).

| data reader |
data := '{"smalltalk": "cool"}
{"pharo": "cooler"}'.
reader := NeoJSONReader on: data readStream.
Array streamContents: [ :out |
  [ reader atEnd ] whileFalse: [ out nextPut: reader next ] ].

Предотвращение промежуточных структур данных тоже легко, используйте потоковую передачу.

| client reader data networkStream |
(client := ZnClient new)
  streaming: true;
  url: 'https://github.com/NYPL-publicdomain/data-and-utilities/blob/master/items/pd_items_1.ndjson?raw=true';
  get.
networkStream := ZnCharacterReadStream on: client contents.
reader := NeoJSONReader on: networkStream.
data := Array streamContents: [ :out |
  [ reader atEnd ] whileFalse: [ out nextPut: reader next ] ].
client close.
data.

Это заняло пару секунд, в конце концов, это 80 МБ + по сети для 50 тыс. Элементов.

Будет ли это работать, если вы откроете новый ReadWriteStream, сначала напишите на него ${, затем перенаправите на него все содержимое вашего исходного потока, разделенного запятыми, и затем запишите конечный $}. Результирующий поток должен быть хорош для NeoJSON...? Вероятно, это атака STTCPW на проблему, но W важна;-) И она должна быть быстрее и меньше потреблять память, потому что NeoJSON просто сделает один проход...

Просто идея, не пробовал.

Вы можете попробовать что-то вроде этого:

| input reader |
input := FileStream readOnlyFileNamed: 'resources/pd_items_1.ndjson.txt'.
[ 
Array
    streamContents: [ :strm | 
        | ln |
        [ (ln := input nextLine) isNil ] 
          whileFalse: [ strm nextPut: (NeoJSONReader fromString: ln) ] ] ] timeToRun.

Если только это не то, что вы уже пробовали...

Другие вопросы по тегам