Repository navigation
insert_many and create_vertices: check the rows in the one json.dumps pass, not in a loop before it (refs #318) - #330
Merged
Conversation
… pass, not in a loop before it (refs #318) json_bulk_dumps and json_bulk_dumps_tagged walked every value of every row in Python before json.dumps walked the rows again. The rows are now written once and the checks come from what that pass shows: the text (a surrogate escape, an integer token of 2**63 and above) and a census of the types of the keys and values in C. The exact per-row walk (_check_rows) is the reference and runs only when a value may be bad, and when json.dumps itself refuses the rows, so the exception type and message for the first bad row in row order are the old loop's. Fuzzed against the old code: 60000 cases, no difference. JVM GraphBatch.create_vertices: classify_vertex_rows decides the shapes by type census instead of a json_bulk_scalar_ok call per value; a scalar the text would change (NaN, integer beyond 64 bits, lone surrogate, subnormal) now sends its own chunk through the property-matrix path, as a tagged chunk already did. The untagged path now also refuses a subnormal, as the tagged one did. NativeGraphBatch: the dead _create_vertices_json_bulk is deleted, and the row type check is a C census. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ed query (refs #318) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…(no json.dumps __context__); test the stored type across chunks (refs #318) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… it has several chunks (refs #318) A bad scalar in a later chunk used to send only that chunk through the property-matrix path, which stores a Python int as a Long while the JSON chunks store an Integer: one undeclared property got two Java types in one call. An input of more than one chunk now has its columns of exact scalars screened in C over the whole input first (type census, joined text of a str column, min and max of an int column, one float64 array for a float column, in blocks of 100,000 rows); a column that may hold a bad value is judged value by value as before, so a bad scalar anywhere sends the whole input the matrix way, as before #330. One chunk is decided by its own dumps before anything is sent. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2 of 3 tasks
abhirajadhikary06
pushed a commit
to abhirajadhikary06/arcadedb-python
that referenced
this pull request
Nov 10, 2026
…ows checked in the one json.dumps pass, whole input decided before chunks) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
abhirajadhikary06
pushed a commit
to abhirajadhikary06/arcadedb-python
that referenced
this pull request
Nov 10, 2026
… float[] and float32 arrays cross as one matrix per property) Conflicts, two: - tests/conftest.py: both sides added a native-only registration at the same spot; both kept, each once. - src/arcadedb/type_conversion.py classify_vertex_rows, the per-column shortcut: ArcadeData#330 (7e81170) screens the exact-scalar columns of an input of several chunks in C (screen_scalars, _scalar_screen) and judges a suspect column value by value; ArcadeData#339 lets a declared column of vectors (now also Java float[] and double[]) and a column of float32 arrays or Java float[] skip the walk. Merged: an exact-scalar column continues unless screen_scalars and the screen flags it; a column with other types skips the walk when it is a declared vector column (_is_vector_kind) or a column of float arrays (_is_float_array_kind), in both modes, so a multi-chunk create_vertices with float32 columns keeps the one-matrix-per-property path. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
abhirajadhikary06
pushed a commit
to abhirajadhikary06/arcadedb-python
that referenced
this pull request
Nov 10, 2026
…cc08cf: column screen for create_vertices, vector blocks) Conflict: src/arcadedb/type_conversion.py _classify_rows, the per-column shortcut. Candidate 3 had my merge of ArcadeData#330 7e81170 (screen_scalars) and the first ArcadeData#339 (vector shortcuts); the new ArcadeData#339 head contains ArcadeData#330 itself and replaces the scalar screen by _screen_key (one list and one census per block, with the suspect flag) and tracks 'vetted'. Took the ArcadeData#339 side: it keeps both behaviours (a flagged scalar column is judged by value, declared vector columns and float-array columns skip the walk in both modes). type_conversion.py and graph_batch.py equal the ArcadeData#339 head after the merge. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
For users nothing changes in what is stored or in which error a bad row raises.
insert_manyandcreate_verticesnow check their rows during the onejson.dumpspass instead of in a Python loop over every value before it, and the first bad row of a batch still gives the same exception type and message as before. One small difference on the JVM wheel, below.Refs #318, part of #315. This targets
release/26.11.1(the base of the wheels-only26.11.1.post1); the engine, jars and image are untouched.What changed:
type_conversion.py:json_bulk_dumpsandjson_bulk_dumps_taggedwrite the rows once (_dumps_once). Ajson.dumpshook cannot see astror anint(the encoder writes both itself), so the checks come from the text and the types: a surrogate escape or an integer token of 2**63 and above in the text, and a census of the key and value types done in C (set(map(type, chain.from_iterable(...)))). Nothing is copied, so peak memory does not change._check_rows, the exact reference. It runs only when a value may be bad (a hit in the text, a type the census cannot vouch for) and whenjson.dumpsitself refuses the rows. So the exception type and message are the old loop's for the first bad row in row order, and a false alarm costs the walk and nothing else. The old messages name no row index; the tests tell the first bad row from a later one by the value in the message.GraphBatch.create_vertices:classify_vertex_rowsdecides the shapes by a type census instead of callingjson_bulk_scalar_okon every value. The rule for a bad scalar (a NaN, an integer beyond 64 bits, a lone surrogate, a subnormal) is the one the code had before: it sends the WHOLE input through the property-matrix path, so the stored type of a property never depends on which chunk held a bad value (the matrix path stores a Python int as a Long and the JSON text as an Integer, and a first version of this PR let one call store both; a CI test caught it). An input of one chunk (at most 100,000 rows) is decided by its own single dumps pass before anything is sent. An input of several chunks first screens its columns of exact scalars in C over the whole input, in blocks of 100,000 rows (type census, the joined text of a str column, min and max of an int column, one float64 array for a float column), and a column that may hold a bad value is judged value by value as the old loop did. So only inputs of several chunks pay a pass besides the dumps, and that pass is not the old per-value loop. The untagged path also refuses a subnormal now, as the tagged path did (the engine reads the text of a subnormal as a DECIMAL). A tagged value that fails inside a chunk (a NaN in a list, a date-time inside a map) still sends only its own chunk the matrix way, as it did before this PR.json.dumpsitself refuses the rows (a NaN in a later row, say) and the walk then finds an earlier bad row, the walk's error is raised outside theexceptblock, so it carries nojson.dumpserror as__context__(a test checks that). The traceback of the first bad row's error is the one the old loop gave, plus the frames of_dumps_once.NativeGraphBatch._create_vertices_json_bulkis deleted, and the row type check increate_verticesis a C census.insert_manyon both wheels gets the change throughjson_bulk_dumps_tagged.Not touched:
new_edges(its own per-value loop), the columnar andbulk.pypaths, andrecords.py.Tests, which run in CI only:
tests/test_bulk_single_pass_validation.py(both wheels) copies the old loop as a private reference and compares text or exception type and message over 52 shaped cases and 6000 random rows, tagged and untagged. It checks the first bad row of a 20,000-row batch for seven kinds of bad value, the boundaries of the 64-bit pattern, and spies on_check_rowsto show that scalar and tagged rows, with the lookalikes (19-digit ints below 2**63, floats with long digit runs, Hangul, CJK, NUL), are not walked while a value that may be bad is. It also stores a 25,000-row scalar batch throughinsert_manyandcreate_vertices.tests/test_graph_batch_single_pass.py(JVM wheel) shows that a scalar table is not judged value by value, that a name or type the text does not carry still sends the whole input the matrix way, and that a subnormal, NaN, big integer or lone surrogate sends only its own chunk.tests/test_graph_batch_single_pass.pyalso loads 250,000 rows with an undeclared int property and a NaN in another property of one row in the first, the middle and the last chunk, checks that the whole input takes the matrix path once, and compares the stored type (k.javaType()) and value of that int property across the chunks; a clean input of three chunks is checked too.test_bulk_json_paths.pyandtest_graph_batch_tagged_shapes.pyare adjusted where they asserted the old whole-input behaviour or spied on the old call site.I made no speed claim here. The measurement is the untimed profile study (queued) and a later laptop A/B; I will report there whether the gain exists.
🤖 Generated with Claude Code