From 7eec78726e0d02696420be8af5c8d54c73c1b709 Mon Sep 17 00:00:00 2001 From: Taewoon Kim Date: Thu, 5 Nov 2026 08:48:53 +0900 Subject: [PATCH] Docs: native find_nearest sends the query as one float32 buffer (#203) Describe the #203 behavior where users read about find_nearest: a paragraph and the A/B table in vectors.adoc (figures copied by script from the study's score file, p50 B/A with 95% intervals), a pointer from the statement-only "A query vector" section, and the query_vector Args text of find_nearest. The find_nearest_approximate Args stay as they are: its native path (_run_approximate) does not use the float32 buffer. The which-package vector-search medians predate #203, so they are labelled as measured before it instead of being replaced by numbers that were not re-measured. The sentence with the find_nearest signature is untouched so the include_vector change (#204) rebases cleanly. Closes #249 Co-Authored-By: Claude Opus 5.5 --- .../pages/how-to/databases-and-queries.adoc | 2 +- docs/modules/ROOT/pages/how-to/vectors.adoc | 24 +++++++++++++++++++ docs/modules/ROOT/pages/which-package.adoc | 2 +- src/arcadedb/vector.py | 3 ++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/how-to/databases-and-queries.adoc b/docs/modules/ROOT/pages/how-to/databases-and-queries.adoc index ba9d927d..3413d0e8 100644 --- a/docs/modules/ROOT/pages/how-to/databases-and-queries.adoc +++ b/docs/modules/ROOT/pages/how-to/databases-and-queries.adoc @@ -226,7 +226,7 @@ The bindings' check counts the `?`, `$` and `:` characters of the SQL text, so i ==== A query vector -A query vector for `vectorNeighbors` can be a numpy array or a list. The conversion before the statement runs is the cost to watch: a query takes about 0.3 to 0.75 ms, and a vector of 1536 numbers took 0.5 to 0.6 ms to convert when it was a list. +A query vector for `vectorNeighbors` can be a numpy array or a list. This section is about statements: `VectorIndex.find_nearest` on the native package converts any numeric query to one `float32` buffer itself, see xref:how-to/vectors.adoc#find-nearest[find_nearest]. The conversion before the statement runs is the cost to watch: a query takes about 0.3 to 0.75 ms, and a vector of 1536 numbers took 0.5 to 0.6 ms to convert when it was a list. * A `float32` array crosses as one buffer on both builds: about 5 to 15 us. This is the fast path. `np.asarray(v, dtype=np.float32)` makes it from a list or from another array. * A list that holds only Python floats (no `int`, `bool`, `None`, `str` or numpy scalar) also crosses as one buffer. The statement reads the same list of doubles it always read: no value changes, and an `int` in a list stays an `int`. A list shorter than 32 numbers (JVM build) or 64 numbers (native build) is not worth a buffer and goes number by number. On the native build the list crosses as a buffer only when `float32` holds every number exactly, which is true of a list from a float32 model (`array.tolist()`); a list of other doubles, `NaN` or an infinity is sent as text, because a buffer would round it. diff --git a/docs/modules/ROOT/pages/how-to/vectors.adoc b/docs/modules/ROOT/pages/how-to/vectors.adoc index 8f55fa4c..df066b24 100644 --- a/docs/modules/ROOT/pages/how-to/vectors.adoc +++ b/docs/modules/ROOT/pages/how-to/vectors.adoc @@ -159,10 +159,34 @@ print([row["name"] for row in rows]) ['python-ish', 'python'] ---- +[[find-nearest]] === find_nearest `VectorIndex.find_nearest(query_vector, k=10, ef_search=None, allowed_rids=None)` searches without a statement. It takes a list or a NumPy array and returns a list of `(record, distance)` tuples, nearest first. Use it when you already hold the index object, or when you have a list of record ids to search within. +On the native package the query vector crosses as one `float32` buffer whatever its form (a list, a `float64` array, or a `float32` array), so you do not need to convert it first. A vector index stores `float32`, so the numbers are rounded the same way as before. The table gives the median `find_nearest` latency with this change over the median without it (95% interval, below 1 is faster), measured on the native wheel `26.11.1.dev0` on one Linux x86_64 laptop with 11 to 12 clean pairs per figure. The wheel built before this change was the baseline. + +[cols="3,2,2",options="header"] +|=== +| Query passed as | 1536 dimensions | 256 dimensions + +| `find_nearest`, a `float32` array +| 0.951 [0.945, 0.954] +| 0.952 [0.942, 0.96] + +| `find_nearest`, a `float64` array +| 0.616 [0.614, 0.621] +| 0.777 [0.774, 0.781] + +| `find_nearest`, a list of Python floats +| 0.631 [0.627, 0.635] +| 0.792 [0.787, 0.798] + +| `vectorNeighbors` statement with a `float32` array (not changed) +| 1.003 [0.995, 1.014] +| 1.004 [0.991, 1.006] +|=== + [source,python] ---- for record, distance in index.find_nearest(query, k=2): diff --git a/docs/modules/ROOT/pages/which-package.adoc b/docs/modules/ROOT/pages/which-package.adoc index a77d58ad..4688e525 100644 --- a/docs/modules/ROOT/pages/which-package.adoc +++ b/docs/modules/ROOT/pages/which-package.adoc @@ -73,7 +73,7 @@ The API is the same. The runtime is not. These are the differences you can plan | Measure on your own workload. | [[vector-search]]Vector search (`LSM_VECTOR`) -| Slower to build and to query, smaller in memory. Against the JVM build, index builds took 1.28 to 1.62 times as long and median queries 1.22 to 1.87 times as long, and peak memory was 0.51 to 0.67 of the JVM build's (medians, 100,000 vectors of 128, 768 and 1536 dimensions, `26.11.1.dev0`, one laptop, with the Highway kernels that are the default on Linux, see xref:how-to/vectors.adoc#native-provider[Distance kernels in the native package]). +| Slower to build and to query, smaller in memory. Against the JVM build, index builds took 1.28 to 1.62 times as long and median queries 1.22 to 1.87 times as long, and peak memory was 0.51 to 0.67 of the JVM build's (medians, 100,000 vectors of 128, 768 and 1536 dimensions, `26.11.1.dev0`, one laptop, measured before the change that makes native `find_nearest` send its query as one `float32` buffer (#203), with the Highway kernels that are the default on Linux, see xref:how-to/vectors.adoc#native-provider[Distance kernels in the native package]). | Faster to build and to query, larger in memory. | Wheel size diff --git a/src/arcadedb/vector.py b/src/arcadedb/vector.py index f2c69dc9..ddc8b32b 100644 --- a/src/arcadedb/vector.py +++ b/src/arcadedb/vector.py @@ -598,7 +598,8 @@ def find_nearest( option, use ``vectorNeighbors`` in SQL. Args: - query_vector: Query vector as Python list, NumPy array, or array-like + query_vector: Query vector as Python list, NumPy array, or array-like (on the + native build it crosses as one float32 buffer in any of these forms) k: Number of nearest neighbors to return (final k). Default is 10. ef_search: Optional search beam width override for exact graph search. None uses the Java index default/adaptive behavior.