From ac95758f7623478ea5746a548eca17708bb26541 Mon Sep 17 00:00:00 2001 From: KaguraMilet Date: Mon, 7 Jul 2025 21:08:24 +0800 Subject: [PATCH] feat(vector): integrate euclidean distance into limbo --- COMPAT.md | 1 + core/function.rs | 4 ++++ core/translate/expr.rs | 13 +++++++++++++ core/vdbe/execute.rs | 7 ++++++- core/vector/distance/euclidean.rs | 2 +- core/vector/mod.rs | 14 ++++++++++++++ 6 files changed, 39 insertions(+), 2 deletions(-) diff --git a/COMPAT.md b/COMPAT.md index 9af20074d..2053be0fd 100644 --- a/COMPAT.md +++ b/COMPAT.md @@ -633,6 +633,7 @@ The `vector` extension is compatible with libSQL native vector search. | vector64(x) | Yes | | | vector_extract(x) | Yes | | | vector_distance_cos(x, y) | Yes | | +| distance_l2(x, y) | Yes |Euclidean distance| ### Time diff --git a/core/function.rs b/core/function.rs index 7827e6307..03c731f86 100644 --- a/core/function.rs +++ b/core/function.rs @@ -156,6 +156,7 @@ pub enum VectorFunc { Vector64, VectorExtract, VectorDistanceCos, + VectorDistanceEuclidean, } impl VectorFunc { @@ -172,6 +173,8 @@ impl Display for VectorFunc { Self::Vector64 => "vector64".to_string(), Self::VectorExtract => "vector_extract".to_string(), Self::VectorDistanceCos => "vector_distance_cos".to_string(), + // We use `distance_l2` to reduce user input + Self::VectorDistanceEuclidean => "distance_l2".to_string(), }; write!(f, "{}", str) } @@ -814,6 +817,7 @@ impl Func { "vector64" => Ok(Self::Vector(VectorFunc::Vector64)), "vector_extract" => Ok(Self::Vector(VectorFunc::VectorExtract)), "vector_distance_cos" => Ok(Self::Vector(VectorFunc::VectorDistanceCos)), + "distance_l2" => Ok(Self::Vector(VectorFunc::VectorDistanceEuclidean)), _ => crate::bail_parse_error!("no such function: {}", name), } } diff --git a/core/translate/expr.rs b/core/translate/expr.rs index b64a14b64..ac6846daf 100644 --- a/core/translate/expr.rs +++ b/core/translate/expr.rs @@ -920,6 +920,19 @@ pub fn translate_expr( }); Ok(target_register) } + VectorFunc::VectorDistanceEuclidean => { + let args = expect_arguments_exact!(args, 2, vector_func); + let regs = program.alloc_registers(2); + translate_expr(program, referenced_tables, &args[0], regs, resolver)?; + translate_expr(program, referenced_tables, &args[1], regs + 1, resolver)?; + program.emit_insn(Insn::Function { + constant_mask: 0, + start_reg: regs, + dest: target_register, + func: func_ctx, + }); + Ok(target_register) + } }, Func::Scalar(srf) => { match srf { diff --git a/core/vdbe/execute.rs b/core/vdbe/execute.rs index 687e39641..98c30c312 100644 --- a/core/vdbe/execute.rs +++ b/core/vdbe/execute.rs @@ -48,7 +48,7 @@ use crate::{ builder::CursorType, insn::{IdxInsertFlags, Insn}, }, - vector::{vector32, vector64, vector_distance_cos, vector_extract}, + vector::{vector32, vector64, vector_distance_cos, vector_distance_l2, vector_extract}, }; use crate::{ @@ -3802,6 +3802,11 @@ pub fn op_function( vector_distance_cos(&state.registers[*start_reg..*start_reg + arg_count])?; state.registers[*dest] = Register::Value(result); } + VectorFunc::VectorDistanceEuclidean => { + let result = + vector_distance_l2(&state.registers[*start_reg..*start_reg + arg_count])?; + state.registers[*dest] = Register::Value(result); + } }, crate::function::Func::External(f) => match f.func { ExtFunc::Scalar(f) => { diff --git a/core/vector/distance/euclidean.rs b/core/vector/distance/euclidean.rs index cfe036a0d..e4b96fd96 100644 --- a/core/vector/distance/euclidean.rs +++ b/core/vector/distance/euclidean.rs @@ -42,7 +42,7 @@ impl DistanceCalculator for Euclidean { _v1: &'a [Vector], _v2: &'a [Vector], ) -> Box> + 'a> { - unimplemented!(); + todo!() } } diff --git a/core/vector/mod.rs b/core/vector/mod.rs index 207af44f0..aab2b7afb 100644 --- a/core/vector/mod.rs +++ b/core/vector/mod.rs @@ -1,5 +1,6 @@ use crate::types::Value; use crate::vdbe::Register; +use crate::vector::distance::{euclidean::Euclidean, DistanceCalculator}; use crate::LimboError; use crate::Result; @@ -78,3 +79,16 @@ pub fn vector_distance_cos(args: &[Register]) -> Result { let dist = do_vector_distance_cos(&x, &y)?; Ok(Value::Float(dist)) } + +pub fn vector_distance_l2(args: &[Register]) -> Result { + if args.len() != 2 { + return Err(LimboError::ConversionError( + "distance_l2 requires exactly two arguments".to_string(), + )); + } + + let x = parse_vector(&args[0], None)?; + let y = parse_vector(&args[1], None)?; + let dist = Euclidean::calculate(&[x], &[y])?; + Ok(Value::Float(dist)) +}