FoundationDB Records layer uses global schema for JSON documents. They also have a nice way of creating indexes and schema evolution support. However this support comes at a cost of extra lookups in different subspace. With local mapping table we almost (except a corner case) certain that the schema and JSON fields would be collocated on a single node. Due to common prefix.
Best regards, iilyak On 2019/01/30 17:05:01, Jan Lehnardt <j...@apache.org> wrote: > Ah sure, if we store the *cough* schema per doc, then it's not that easy. An > iteration of this proposal could store paths globally with ids that the k/v > store then uses for keys, which would enable what I described, but happy to > ignore this for the time being. :) > > Cheers > Jan > — > > > On 30. Jan 2019, at 17:58, Adam Kocoloski <kocol...@apache.org> wrote: > > > > Jan, I don’t think it does have that "fun property #2", as the mapping is > > created separately for each document. In this proposal the field name “foo” > > could map to 2 in one document and 42 in another. > > > > Thanks for the proposal Ilya. Personally I wonder if the 10KB limit on > > field paths is anything more than a theoretical concern. It’s hard for me > > to imagine a useful schema that would get anywhere near that deep, but > > maybe I’m insufficiently creative :) There’s certainly a storage overhead > > from repeating the upper portion of a path over and over again, but that’s > > also something the storage engine can optimize away through prefix elision. > > The current production storage engine in FoundationDB does not do this > > elision, but the new one in development does. > > > > The value size limit is probably not so theoretical. I think as a project > > we could choose to impose a 100KB size limit on scalar values - a user who > > had a string longer than 100KB could chunk it up into an array of strings > > pretty easily to work around that limit. But let’s say we don’t want to > > impose that limit. In your design, how do I distinguish {PART_IDX} from the > > elements of the {JSON_PATH}? I was kind of expecting to see some magic > > value indicating that the subsequent set of keys with the same prefix are > > all elements of a “multi-part object”: > > > > {DB_DOCS_NS} / {DOC_KEY} / {JSON_PATH} = kMULTIPART > > {DB_DOCS_NS} / {DOC_KEY} / {JSON_PATH} / {PART_IDX} = “First 100 KB …" > > ... > > > > You might have figured out something more efficient that saves a KV here > > but I can’t quite grok it. > > > > Cheers, Adam > > > > > >> On Jan 30, 2019, at 8:24 AM, Jan Lehnardt <j...@apache.org> wrote: > >> > >> > >> > >>> On 30. Jan 2019, at 14:22, Jan Lehnardt <j...@apache.org > >>> <mailto:j...@apache.org>> wrote: > >>> > >>> Thanks Ilya for getting this started! > >>> > >>> Two quick notes on this one: > >>> > >>> 1. note that JSON does not guarantee object key order and that CouchDB > >>> has never guaranteed it either, and with say emit(doc.foo, doc.bar), if > >>> either emit() parameter was an object, the undefined-sort-order of > >>> SpiderMonkey would mix things up. While worth bringing up, this is not a > >>> BC break. > >>> > >>> 2. This would have the fun property of being able to rename a key inside > >>> all docs that have that key. > >> > >> …in one short operation. > >> > >> Best > >> Jan > >> — > >>> > >>> Best > >>> Jan > >>> — > >>> > >>>> On 30. Jan 2019, at 14:05, Ilya Khlopotov <iil...@apache.org> wrote: > >>>> > >>>> # First proposal > >>>> > >>>> In order to overcome FoudationDB limitations on key size (10 kB) and > >>>> value size (100 kB) we could use the following approach. > >>>> > >>>> Bellow the paths are using slash for illustration purposes only. We can > >>>> use nested subspaces, tuples, directories or something else. > >>>> > >>>> - Store documents in a subspace or directory (to keep prefix for a key > >>>> short) > >>>> - When we store the document we would enumerate all field names (0 and 1 > >>>> are reserved) and store the mapping table in the key which look like: > >>>> ``` > >>>> {DB_DOCS_NS} / {DOC_KEY} / 0 > >>>> ``` > >>>> - Flatten the JSON document (convert it into key value pairs where the > >>>> key is `JSON_PATH` and value is `SCALAR_VALUE`) > >>>> - Replace elements of JSON_PATH with integers from mapping table we > >>>> constructed earlier > >>>> - When we have array use `1 / {array_idx}` > >>>> - Store scalar values in the keys which look like the following (we use > >>>> `JSON_PATH` with integers). > >>>> ``` > >>>> {DB_DOCS_NS} / {DOC_KEY} / {JSON_PATH} > >>>> ``` > >>>> - If the scalar value exceeds 100kB we would split it and store every > >>>> part under key constructed as: > >>>> ``` > >>>> {DB_DOCS_NS} / {DOC_KEY} / {JSON_PATH} / {PART_IDX} > >>>> ``` > >>>> > >>>> Since all parts of the documents are stored under a common `{DB_DOCS_NS} > >>>> / {DOC_KEY}` they will be stored on the same server most of the time. > >>>> The document can be retrieved by using range query > >>>> (`txn.get_range("{DB_DOCS_NS} / {DOC_KEY} / 0", "{DB_DOCS_NS} / > >>>> {DOC_KEY} / 0xFF")`). We can reconstruct the document since the mapping > >>>> is returned as well. > >>>> > >>>> The downside of this approach is we wouldn't be able to ensure the same > >>>> order of keys in the JSON object. Currently the `jiffy` JSON encoder > >>>> respects order of keys. > >>>> ``` > >>>> 4> jiffy:encode({[{bbb, 1}, {aaa, 12}]}). > >>>> <<"{\"bbb\":1,\"aaa\":12}">> > >>>> 5> jiffy:encode({[{aaa, 12}, {bbb, 1}]}). > >>>> <<"{\"aaa\":12,\"bbb\":1}">> > >>>> ``` > >>>> > >>>> Best regards, > >>>> iilyak > >>>> > >>>>> On 2019/01/30 13:02:57, Ilya Khlopotov <iil...@apache.org> wrote: > >>>>> As you might already know the FoundationDB has a number of limitations > >>>>> which influences the way we might store JSON documents. The limitations > >>>>> are: > >>>>> > >>>>> | limitation |recommended value|recommended > >>>>> max|absolute max| > >>>>> |-------------------------|----------------------:|--------------------:|--------------:| > >>>>> | transaction duration | | > >>>>> | 5 sec | > >>>>> | transaction data size | | > >>>>> | 10 Mb | > >>>>> | key size | 32 bytes | > >>>>> 1 kB | 10 kB | > >>>>> | value size | | > >>>>> 10 kB | 100 kB | > >>>>> > >>>>> In order to fit the JSON document into 100kB we would have to partition > >>>>> it in some way. There are three ways of partitioning the document > >>>>> 1. store multiple binary blobs (parts) in different keys > >>>>> 2. flatten JSON structure and store every path leading to a scalar > >>>>> value under own key > >>>>> 3. measure the size of different branches of a tree representing the > >>>>> JSON document (while we parse) and use another key for the branch when > >>>>> we about to exceed the limit > >>>>> > >>>>> - The first approach is the simplest but it wouldn't allow us to access > >>>>> parts of the document. > >>>>> - The downsides of a second approach are: > >>>>> - flattened JSON structure would have long paths which means longer keys > >>>>> - the scalar value cannot be more than 100kb (unless we split it as > >>>>> well) > >>>>> - Third approach falls short in cases when the structure of the > >>>>> document doesn't allow a clean cut off branches: > >>>>> - complex rules to handle all corner cases > >>>>> > >>>>> The goals of this thread are: > >>>>> - to collect ideas on how to encode and store the JSON document > >>>>> - to comment on the collected ideas > >>>>> > >>>>> Non goals: > >>>>> - the storage of metadata for the document would be discussed elsewhere > >>>>> - thumb stones > >>>>> - edit conflicts > >>>>> - revisions > >>>>> > >>>>> Best regards, > >>>>> iilyak > >>>>> > >>> > >>> -- > >>> Professional Support for Apache CouchDB: > >>> https://neighbourhood.ie/couchdb-support/ > >>> > >> > >> -- > >> Professional Support for Apache CouchDB: > >> https://neighbourhood.ie/couchdb-support/ > >> <https://neighbourhood.ie/couchdb-support/> > >