Как разобрать 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.
Если только это не то, что вы уже пробовали...