Add exact search to vectorDB

This commit is contained in:
laurenspriem
2025-08-01 16:55:02 +02:00
parent 9528b4ce8d
commit 6dfcc58144
6 changed files with 184 additions and 44 deletions

View File

@@ -22,7 +22,9 @@ abstract class VectorDb implements RustOpaqueInterface {
Future<BigInt> bulkRemoveVectors({required Uint64List keys});
Future<(List<Uint64List>, List<Float32List>)> bulkSearchVectors(
{required List<Float32List> queries, required BigInt count});
{required List<Float32List> queries,
required BigInt count,
required bool exact});
/// Check if a vector with the given key exists in the index.
/// `true` if the index contains the vector with the given key, `false` otherwise.
@@ -44,5 +46,7 @@ abstract class VectorDb implements RustOpaqueInterface {
Future<void> resetIndex();
Future<(Uint64List, Float32List)> searchVectors(
{required List<double> query, required BigInt count});
{required List<double> query,
required BigInt count,
required bool exact});
}

View File

@@ -105,7 +105,8 @@ abstract class RustLibApi extends BaseApi {
crateApiUsearchApiVectorDbBulkSearchVectors(
{required VectorDb that,
required List<Float32List> queries,
required BigInt count});
required BigInt count,
required bool exact});
Future<bool> crateApiUsearchApiVectorDbContainsVector(
{required VectorDb that, required BigInt key});
@@ -129,7 +130,8 @@ abstract class RustLibApi extends BaseApi {
Future<(Uint64List, Float32List)> crateApiUsearchApiVectorDbSearchVectors(
{required VectorDb that,
required List<double> query,
required BigInt count});
required BigInt count,
required bool exact});
String crateApiSimpleGreet({required String name});
@@ -275,7 +277,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
crateApiUsearchApiVectorDbBulkSearchVectors(
{required VectorDb that,
required List<Float32List> queries,
required BigInt count}) {
required BigInt count,
required bool exact}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
@@ -283,6 +286,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
that, serializer);
sse_encode_list_list_prim_f_32_strict(queries, serializer);
sse_encode_usize(count, serializer);
sse_encode_bool(exact, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
funcId: 5, port: port_);
},
@@ -292,7 +296,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
decodeErrorData: null,
),
constMeta: kCrateApiUsearchApiVectorDbBulkSearchVectorsConstMeta,
argValues: [that, queries, count],
argValues: [that, queries, count, exact],
apiImpl: this,
));
}
@@ -300,7 +304,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiUsearchApiVectorDbBulkSearchVectorsConstMeta =>
const TaskConstMeta(
debugName: "VectorDb_bulk_search_vectors",
argNames: ["that", "queries", "count"],
argNames: ["that", "queries", "count", "exact"],
);
@override
@@ -498,7 +502,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
Future<(Uint64List, Float32List)> crateApiUsearchApiVectorDbSearchVectors(
{required VectorDb that,
required List<double> query,
required BigInt count}) {
required BigInt count,
required bool exact}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding);
@@ -506,6 +511,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
that, serializer);
sse_encode_list_prim_f_32_loose(query, serializer);
sse_encode_usize(count, serializer);
sse_encode_bool(exact, serializer);
pdeCallFfi(generalizedFrbRustBinding, serializer,
funcId: 13, port: port_);
},
@@ -515,7 +521,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
decodeErrorData: null,
),
constMeta: kCrateApiUsearchApiVectorDbSearchVectorsConstMeta,
argValues: [that, query, count],
argValues: [that, query, count, exact],
apiImpl: this,
));
}
@@ -523,7 +529,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
TaskConstMeta get kCrateApiUsearchApiVectorDbSearchVectorsConstMeta =>
const TaskConstMeta(
debugName: "VectorDb_search_vectors",
argNames: ["that", "query", "count"],
argNames: ["that", "query", "count", "exact"],
);
@override
@@ -1103,9 +1109,11 @@ class VectorDbImpl extends RustOpaque implements VectorDb {
.crateApiUsearchApiVectorDbBulkRemoveVectors(that: this, keys: keys);
Future<(List<Uint64List>, List<Float32List>)> bulkSearchVectors(
{required List<Float32List> queries, required BigInt count}) =>
{required List<Float32List> queries,
required BigInt count,
required bool exact}) =>
RustLib.instance.api.crateApiUsearchApiVectorDbBulkSearchVectors(
that: this, queries: queries, count: count);
that: this, queries: queries, count: count, exact: exact);
/// Check if a vector with the given key exists in the index.
/// `true` if the index contains the vector with the given key, `false` otherwise.
@@ -1135,7 +1143,9 @@ class VectorDbImpl extends RustOpaque implements VectorDb {
);
Future<(Uint64List, Float32List)> searchVectors(
{required List<double> query, required BigInt count}) =>
{required List<double> query,
required BigInt count,
required bool exact}) =>
RustLib.instance.api.crateApiUsearchApiVectorDbSearchVectors(
that: this, query: query, count: count);
that: this, query: query, count: count, exact: exact);
}

View File

@@ -54,6 +54,12 @@ dependencies = [
"log",
]
[[package]]
name = "anstyle"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anyhow"
version = "1.0.75"
@@ -142,11 +148,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
name = "clap"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
dependencies = [
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_lex"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "codespan-reporting"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
dependencies = [
"serde",
"termcolor",
"unicode-width",
]
@@ -173,25 +206,27 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.112"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ab30434ea0ff6aa640a08dda5284026a366d47565496fd40b6cbfbdd7e31a2"
checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df"
dependencies = [
"cc",
"cxxbridge-cmd",
"cxxbridge-flags",
"cxxbridge-macro",
"foldhash",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.112"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b649d7dfae8268450d53d109388b337b9352c7cba1fc10db4a1bc23c3dc189fb"
checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"indexmap",
"proc-macro2",
"quote",
"scratch",
@@ -199,19 +234,35 @@ dependencies = [
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.112"
name = "cxxbridge-cmd"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42281b20eba5218c539295c667c18e2f50211bb11902419194c6ed1ae808e547"
checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a"
dependencies = [
"clap",
"codespan-reporting",
"indexmap",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d"
[[package]]
name = "cxxbridge-macro"
version = "1.0.112"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45506e3c66512b0a65d291a6b452128b7b1dd9841e20d1e151addbd2c00ea50"
checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4"
dependencies = [
"indexmap",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
@@ -231,7 +282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
dependencies = [
"cfg-if",
"hashbrown",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core",
@@ -268,6 +319,12 @@ dependencies = [
"regex",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "flutter_rust_bridge"
version = "2.11.1"
@@ -310,6 +367,12 @@ dependencies = [
"syn",
]
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "futures"
version = "0.3.29"
@@ -421,6 +484,12 @@ version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "hermit-abi"
version = "0.3.3"
@@ -433,6 +502,16 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "indexmap"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown 0.15.4",
]
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -573,18 +652,18 @@ checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "proc-macro2"
version = "1.0.70"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
@@ -641,6 +720,12 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -653,6 +738,26 @@ version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "slab"
version = "0.4.9"
@@ -669,10 +774,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "syn"
version = "2.0.39"
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@@ -728,9 +839,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "usearch"
version = "2.17.11"
version = "2.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "908331accde6ff6bfe83e1f2dfd4cc77343d107bfacecd2f19b7a14d87cdb2df"
checksum = "afa869be4baf62146b39700da30b235b06f58d2c03b7e073a8e2b57e0f511aa9"
dependencies = [
"cxx",
"cxx-build",

View File

@@ -8,7 +8,7 @@ crate-type = ["cdylib", "staticlib"]
[dependencies]
flutter_rust_bridge = "=2.11.1"
usearch = "2.17.11"
usearch = "2.19.1"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] }

View File

@@ -83,11 +83,21 @@ impl VectorDB {
self.save_index();
}
pub fn search_vectors(&self, query: &Vec<f32>, count: usize) -> (Vec<u64>, Vec<f32>) {
let matches = self
.index
.search(query, count)
.expect("Failed to search vectors");
pub fn search_vectors(
&self,
query: &Vec<f32>,
count: usize,
exact: bool,
) -> (Vec<u64>, Vec<f32>) {
let matches = if exact {
self.index
.exact_search(query, count)
.expect("Failed to exact search vectors")
} else {
self.index
.search(query, count)
.expect("Failed to search vectors")
};
(matches.keys, matches.distances)
}
@@ -95,12 +105,13 @@ impl VectorDB {
&self,
queries: &Vec<Vec<f32>>,
count: usize,
exact: bool,
) -> (Vec<Vec<u64>>, Vec<Vec<f32>>) {
let mut keys = Vec::new();
let mut distances = Vec::new();
for query in queries {
let (keys_result, distances_result) = self.search_vectors(query, count);
let (keys_result, distances_result) = self.search_vectors(query, count, exact);
keys.push(keys_result);
distances.push(distances_result);
}

View File

@@ -296,6 +296,7 @@ fn wire__crate__api__usearch_api__VectorDb_bulk_search_vectors_impl(
>>::sse_decode(&mut deserializer);
let api_queries = <Vec<Vec<f32>>>::sse_decode(&mut deserializer);
let api_count = <usize>::sse_decode(&mut deserializer);
let api_exact = <bool>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, ()>((move || {
@@ -318,6 +319,7 @@ fn wire__crate__api__usearch_api__VectorDb_bulk_search_vectors_impl(
&*api_that_guard,
&api_queries,
api_count,
api_exact,
),
)?;
Ok(output_ok)
@@ -682,6 +684,7 @@ fn wire__crate__api__usearch_api__VectorDb_search_vectors_impl(
>>::sse_decode(&mut deserializer);
let api_query = <Vec<f32>>::sse_decode(&mut deserializer);
let api_count = <usize>::sse_decode(&mut deserializer);
let api_exact = <bool>::sse_decode(&mut deserializer);
deserializer.end();
move |context| {
transform_result_sse::<_, ()>((move || {
@@ -704,6 +707,7 @@ fn wire__crate__api__usearch_api__VectorDb_search_vectors_impl(
&*api_that_guard,
&api_query,
api_count,
api_exact,
))?;
Ok(output_ok)
})())