Repository navigation
insert_many: date-times, Decimals, bytes, numpy scalars and pandas NA stay on the bulk path; an uncarriable value moves its own row, not the chunk - #82
Merged
Conversation
…o longer moves its 10,000-row chunk to the per-row path
A datetime, date, Decimal, bytes, numpy scalar, pandas NA or NaT sitting directly in a row now crosses inside the JSON text as a tagged value ({"\u0001": [kind, payload]}) that DocumentBatcher.fill decodes to the objects the per-row path builds (LocalDateTime, LocalDate, BigDecimal, byte[]). A value the text still cannot carry (NaN, Infinity, an integer beyond 64 bits, a date-time inside a list or map, a lone surrogate, a datetime.time) sends only its own row down the per-row path, in order, and the rows around it stay on the bulk path. The parallel mode does the same. Port of humemai/arcadedb-embedded-python#528.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: DocumentBatcher.java header (kept both paragraphs) and core.py (insert_many fallback: the per-row helper creates vertices for a vertex type, as main's fallback does). Same tree as the rebased branch that the tests ran on. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
tae898
marked this pull request as ready for review
October 26, 2026 15:45
…re strict xfail on native The native parity job failed 8 of the 14 new tests: it has its own per-row path that never calls Database.new_document, so the three non-zero counts (only the uncarriable row goes per row) now run on the JVM wheel only, with the stored-value comparison on both. The native build refuses pandas NA/NaT and numpy datetime64 as parameters (TypeError), recorded as strict xfail naming the backlog row so it turns red when native supports them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ead of a strict xfail The native parity gate counts an xfail as an uncounted skip (parity_wheel.py counts every <skipped>), so the two strict xfail rows made it fail with skipped=2 although all 1520 tests passed. On native the two tests now assert the TypeError the native build raises today and return; they turn red the day native accepts these values. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
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.
Moved from #50: the personal fork was retired; same commits.
This is the port of humemai/arcadedb-embedded-python#528 (package
arcadedb, no "embedded" names).insert_manysends each 10,000-row chunk to the engine as one JSON text. Until nowjson.dumpsraised on adatetime,date,Decimal,bytes, a numpy scalar or a pandasNA/NaT, and one such value anywhere in a chunk sent the whole chunk down the per-row path (new_document+setper property +save, about 10 JPype crossings per row). Real tables nearly always carry a timestamp or a decimal, so most loads never reached the bulk path (backlog rows N-04, J-04, J-05).What changes
{"\^A": [kind, payload]}:T(datetime, as the UTC wall clock the per-row path stores),D(date),n(Decimal),b(bytes, base64).DocumentBatcher.filldecodes the tag to the objectconvert_python_to_javabuilds for the per-row path (LocalDateTime,LocalDate,BigDecimal,byte[]). Numpy scalars cross as plain numbers (np.bool_as a bool),pandas.NA/NaT/np.datetime64('NaT')as null,pandas.Timestampandnp.datetime64as a naivedatetime(microseconds, as the per-row path keeps them).datetime/Decimalinside a list or dict, a non-str dict key, a lone surrogate, adatetime.time, a numpylongdoubleortimedelta64, a non-finiteDecimal. Runs of carriable rows still go in bulk, and every row is inserted in the order given. Inparallel=Truethe uncarriable rows are written synchronously after the writers drain (the writers never kept order).json_bulk_dumps(used byGraphBatch) is unchanged; onlyinsert_manyuses the newjson_bulk_dumps_tagged, because onlyDocumentBatcher.filldecodes the tags. A user dict keyed by the tag marker is refused by the bulk path, so it stays a map.insert_dataframe/insert_arrow/insert_columnswith a null in a numeric column (the other half of J-05) still builds anObject[]element by element. That is a separate Java change (a validity mask), so it gets its own PR.Stored values
tests/test_insert_many_mixed_values.pywrites the same rows through the per-row path and throughinsert_many, into a declared type (DATETIME, DATE, DECIMAL, BINARY, LONG, INTEGER, DOUBLE, FLOAT, BOOLEAN properties) and a schemaless one, and compares the stored value and its Python type for 17 value kinds (naive and UTC+9 datetime, date, Decimal with and without exponent, bytes, bytearray, np.int64/int8/uint32/float64/float32/bool_, None). It countsDatabase.new_documentcalls to prove which path ran, and also coverspandas.Timestamp(naive with nanoseconds, aware),pandas.NA/NaTandnp.datetime64(the per-row path raises for these; the bulk path stores null / a naive datetime), a 10,000-row chunk with one datetime, an uncarriable row in the middle of 1,000 (exactly onenew_documentcall, stored rows equal the per-row path's), insertion order around per-row runs,commit_everyacross chunks, rollback on a failing row,parallel=True, and the tag lookalike. The suite failed 15 of 20 tests before the change.Untimed 1M-row figure
One run each (not through
ab.py, so no claim), fresh process, 1,000,000 rows of six properties with a Pythondatetimeper row, row building inside the timed call, JVM-Xmx4g, throughquiet_build:insert_manytook 31.2 s before (1,000,000new_documentcalls, the whole load on the per-row path) and 7.4 s after (0new_documentcalls). The same rows without thetscolumn take 4.1 s, so the datetime itself now costs about 3.3 s per million rows (JSON text plusLocalDateTime.parse) instead of 27 s. Measured on the humemai fork (humemai/arcadedb-embedded-python#528) with the same change.Local checks
tests/test_insert_many_mixed_values.py20 passed, plustest_bulk_insert.py,test_bulk_json_paths.py,test_float_vector_bulk.py,test_numpy_support.py,test_conversion_fixes.py,test_graph_batch.py,test_insert_columns.py,test_async_executor.py,test_core.py,test_bridge_fixes.py,test_type_conversion.py,test_docs_examples.py,test_check_test_skips.py(all pass) against the engine jars and JRE of the humemai main CI wheel with this branch's Python files and the bridge classes compiled into a copy of the bridge jar (171 passed for the five suites listed first)Docs changed in this PR: the
insert_manydocstring (what is carried, what still goes per row). This repository keeps its API reference in Antora modules that do not describe theinsert_manyfallback, so there is no other page to update.🤖 Generated with Claude Code