Simple - memory-map the whole file with `mmap`. We also suggest using `madvice`, to inform the kernel that you will be accessing the data just once, strictly in the sequential order. And then simply give it to SIMDJSON. With `ondemand` parser, your memory usage will be proportional to the depth of the deepest tree, not their number.
Harder way, would be to parse file in chunks, locating continuous sequences that form a single document.
There may be more options, but I'd have to check the docs :)
If you have any code examples of either of those options I'd love to see them!
Edit: Also, I'm curious: what are the downsides to doing the mmap route?
You can mitigate this somewhat with explicit MAP_POPULATE and mlock.
They're... kinda free (in terms of capacity). A PTE or PDE is 64 bits per page. Even with 4kB pages, this is 8/4096 = 0.2% overhead. Churning the page tables and TLB as you walk the file is expensive, or at least historically was expensive (used to be that removing an entry required flushing the entire TLB; I don't think that's true anymore).
If you can use MAP_HUGE_2MB, this drops off to 0.00038% and the TLB impact goes way down.
> no way of handling errors.
Yeah, this aspect is really significant. Thanks for mentioning it.
When you source the data, can you instead output the overall doc as "part" files that are aligned along subdocument boundaries?
THen you don't have to solve that "find the subdocument terminator" on stream-back.
You are PROBABLY building the json doc via some DB dump, so just change the code that dumps the data.
If you need to reconstruct it as a single json doc for some reason, it is about as trivial as it gets to reconstruct the data as a single document.
Or programattically, a "file" object that just does the reconstruction on the fly from the source part files as it is read, that should be relatively trivial in lots of languages.
If so, it’s easy in Python to do the following:
with open(“file.json”) as src:
for line in src:
json.loads(line)[0] https://github.com/simdjson/simdjson/issues/188#issuecomment...
Whatever remained at the end of the buffer (few hundred bytes of incomplete json) we would copy just before the boost-unzip block so that there was a continuation of json data. We also reused the parser and string buffer for performance.
Also try to parse the json fields in the right order for fastest performance, if possible.
What do you mean with this precisely, not sure I understand? What is the right order?
AFAIK, JSON attributes/keys are not ordered, so there is no "right" order, or order at all.
The docs on simdjson mention that if you parse the fields in the order as they appear on file, then simdjson can do it in one iteration. If you get fields in random order, simdjson will have to loop the data a few times.
If your json on disk is
{ "field1": "val1", "field2": "val2" }
then it is faster to say (pseudo C++) simdjson::document_reference elem;
std::string_view tmp;
elem["field1"].get_string().get(tmp);
elem["field2"]...
than the other way around. This works only if you know what you are looking for and it is consistent on disk. Note that you are reading from an iterator that consumes the value: getting a field twice gives an error; totally different than reading from a dict.See also [1] under "Extracting Values: You can cast a JSON element to a native type..."
[1] https://github.com/simdjson/simdjson/blob/master/doc/basics....
If there is any interest, I can ask if they can to open source it.
Edit: Oh wow, I see you used it on those exact files. How about that.
We needed it for streaming large json from async server sockets.
Code link: https://github.com/Edgio/is2/blob/master/include/is2/support...
You just had to implement the interfaces like Peek/Take/Tell/etc. It worked really well for us.
Probably not as fast as simdjson, but they used some simd tricks I think for skipping whitespace:
https://rapidjson.org/md_doc_internals.html#SkipwhitespaceWi...
And yep, it was more or less they way you did with ijson. I found ijson just a day after I finished the prototype. Rapidjson would probably be faster. Especially after enabling SIMD. But the indexing was a one time thing.
We have open sourced the codebase. Here's the link: https://github.com/multiversal-ventures/json-buffet . Since this was a quick and dirty prototype, comments were sparse. I have updated the Readme, and added a sample json-fetcher. Hope this is more useful for you.
Another unwritten TODO was to nudge the data providers towards a more streaming friendly compression formats - and then just create an index to fetch the data directly from their compressed archives. That would have saved everyone a LOT of $$$.
I've got an idea for how you can do it with parse_many(json,window) and truncated_bytes() but it would be easier if there were just an example out there I could look at.
See pages like [0] and [1] that describe it should be possible but I am just not seeing (or yet able to produce myself) working code.
[0] https://github.com/simdjson/simdjson/issues/188
[1] https://github.com/simdjson/simdjson/blob/master/doc/iterate...