Skip to content

JVM create_vertices: take float[] and double[] vectors through the float32 matrix - #221

Closed
tae898 wants to merge 1 commit into
mainfrom
perf/jvm-create-vertices-jarray
Closed

tae898 wants to merge 1 commit into
mainfrom
perf/jvm-create-vertices-jarray

Conversation

@tae898

@tae898 tae898 commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Closes #220

On the JVM wheel, GraphBatch.create_vertices (and insert_many) now send float vectors given as JPype float[] or double[] (what to_java_float_array returns on that wheel) through the json-bulk plus binary float32 matrix path, instead of declining the whole chunk to _to_java_property_matrix.

The change is in src/arcadedb/type_conversion.py: is_vector_candidate also accepts the two JPype array types (resolved once, after the JVM has started), and split_float_vectors requires every value of a column to be a candidate when its first value is a Java array. No new conversion call: numpy reads a JPype primitive array through the buffer protocol (float[] as float32, double[] as float64, which the split already casts to float32 as for float64 ndarrays), checked on JPype 1.7.1 and numpy 2.5.4. Stored values are bit-identical to the declined path; a JArray(JInt) or JArray(JLong), a null, a missing value, a ragged vector and an empty array keep declining as before. insert_many shares the candidate test and takes the same matrix; insert_columns takes whole columns and does not use it. The native wheel is untouched: to_java_float_array returns a float32 ndarray there (vector.py, _native_enabled() branch) and the new test file is listed in NATIVE_NOT_APPLICABLE.

Tests: tests/test_jvm_vector_jarray.py (19 cases) spies on split_float_vectors and GraphBatch._to_java_property_matrix. Run against the unchanged CI JVM wheel (whose type_conversion.py, graph_batch.py, core.py and vector.py are byte-equal to main 1b315c1), 8 of 19 fail (the cases that need the new path) and 11 pass (the decline guards and the setup checks). The decline guards cannot fail on old code by construction, so they were checked against a mutant that accepts every Java array and drops the all-candidates check: 5 of them fail there. With the change, 19 of 19 pass, and test_float_vector_bulk.py, test_graph_batch.py, test_numpy_support.py, test_type_conversion.py and test_vector_index_introspection.py still pass (164 tests in all).

Timing is not claimed here. Untimed probe figures are in #220 (load time of the to_java_float_array shape was 2.0x to 2.4x that of float32 ndarray rows); a timed one-library A/B follows before this leaves draft.

🤖 Generated with Claude Code

…oat32 matrix (closes #220)

is_vector_candidate accepted only a list or an ndarray, so a chunk of vectors built with to_java_float_array (a JPype float[] on the JVM build) left the json-bulk path for _to_java_property_matrix. A JPype primitive array is read by numpy through the buffer protocol (float[] as float32, double[] as float64), so the candidate test now also accepts those two JPype types and split_float_vectors needs no new conversion. A column that starts with a Java array must hold only candidates; an int[], a long[], a null, a missing value, a ragged or an empty vector keep declining. insert_many shares the test and takes the same matrix. Native is unchanged: to_java_float_array returns a float32 ndarray there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tae898

tae898 commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Timed A/B (JVM build; arm A = main CI JVM wheel built from 413f54f, arm B = A's tree with only type_conversion.py from this PR (A + src/arcadedb/type_conversion.py of PR 221 head 15a11ef), A/A control; laptop timed lane, ab.py --noise, ABBA pairs, 12 clean pairs per figure; the rule written before the run). Load time ratio B/A of create_vertices plus batch close:

shape vectors from to_java_float_array (gating) float32 ndarray rows (control, path not changed by this PR) A/A on the control
128-d, batch 10,000 0.661 [0.628, 0.669] 0.985 [0.919, 1.094] 0.999 [0.930, 1.085]
96-d, batch 10,000 0.632 [0.572, 0.661] 1.105 [0.955, 1.170] 1.044 [0.956, 1.131]
64-d, batch 5,000 0.643 [0.590, 0.723] 0.895 [0.850, 0.942] 0.949 [0.854, 0.992]

By the rule this run is GRAY: every gating interval is below 1.00, but the control's median left [0.97, 1.03] on two shapes, and the rule then makes no speed claim. The control is the float32-ndarray path, which this PR does not change, and its intervals (and the A/A intervals beside them) are wide on this build, so the run did not separate the PR's effect from the noise of that path well enough for the rule.

I will run it once more, unchanged (same arms, same rule, written before this run), and that second run decides: SHIP only if it meets the rule; if it is GRAY again, this PR is reported as not shown to help and left as a draft.

@tae898

tae898 commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator Author

Second timed run (the one declared final in the comment above; same arms, pins, rule and thresholds, 12 clean pairs per figure, B/A median with 95% CI, below 1 = B faster):

shape vectors from to_java_float_array (gating) float32 ndarray rows (control) A/A on the control
128-d, batch 10,000 0.650 [0.627, 0.674] 0.986 [0.835, 1.099] 0.930 [0.894, 1.014]
96-d, batch 10,000 0.608 [0.572, 0.659] 0.950 [0.887, 1.016] 0.956 [0.826, 1.004]
64-d, batch 5,000 0.694 [0.645, 0.737] 0.890 [0.803, 0.929] 0.964 [0.804, 1.120]

By the rule this run is GRAY again: every gating interval is below 1.00, but the control's median is outside [0.97, 1.03] on two shapes. As committed above, this PR is therefore reported as not shown to help by this study, makes no speed claim, and stays draft.

For the record, the control's movement cannot come from this change: for a float32 ndarray is_vector_candidate returns at the isinstance(value, np.ndarray) test before the new float[]/double[] check, and the only other addition is one type test per column. The control is noisy at this size (its own A/A interval is wide on the same shapes), which is a weakness of this study's design, not a finding about the PR. A new study with a quieter control would be a separate pre-registration; none is planned before the 26.11.1 freeze.

@tae898

tae898 commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator Author

Closing without merging: both timed runs above (the second declared final before it ran) came out inconclusive by the rule written before the first run, and speed was the only reason for the change, so the current path stays. The measurements remain here for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JVM create_vertices: float[] vectors from to_java_float_array decline the json-bulk matrix path

1 participant