1- use defs:: { DbError , Dimension , IndexedVector , Similarity , SnapshottableDb } ;
2- use defs:: { DenseVector , Payload , Point , PointId } ;
1+ use defs:: { DbError , Dimension , IndexedVector , SearchQueryInput , Similarity , SnapshottableDb } ;
2+ use defs:: { DenseVector , Payload , Point , PointId , PointInput } ;
33use index:: hnsw:: HnswIndex ;
44use index:: kd_tree:: index:: KDTree ;
55use std:: path:: { Path , PathBuf } ;
@@ -70,6 +70,37 @@ impl VectorDb {
7070 Ok ( point_id)
7171 }
7272
73+ pub fn insert_batch ( & self , points : Vec < PointInput > ) -> Result < Vec < PointId > > {
74+ let mut ids = Vec :: with_capacity ( points. len ( ) ) ;
75+
76+ for point in points {
77+ let id = point. id . unwrap_or_else ( Uuid :: new_v4) ;
78+ let vector = point. vector ;
79+ let payload = point. payload ;
80+
81+ if let Some ( ref v) = vector
82+ && v. len ( ) != self . dimension
83+ {
84+ return Err ( ApiError :: DimensionMismatch {
85+ expected : self . dimension ,
86+ got : v. len ( ) ,
87+ } ) ;
88+ }
89+
90+ self . storage . insert_point ( id, vector. clone ( ) , payload) ?;
91+
92+ if let Some ( v) = vector {
93+ let indexed = IndexedVector { id, vector : v } ;
94+ let mut index = self . index . write ( ) . map_err ( |_| ApiError :: LockError ) ?;
95+ index. insert ( indexed) ?;
96+ }
97+
98+ ids. push ( id) ;
99+ }
100+
101+ Ok ( ids)
102+ }
103+
73104 //TODO: Make this an atomic operation
74105 pub fn delete ( & self , id : PointId ) -> Result < bool > {
75106 // Remove from storage
@@ -95,34 +126,41 @@ impl VectorDb {
95126 }
96127 }
97128
98- pub fn search (
99- & self ,
100- query : DenseVector ,
101- similarity : Similarity ,
102- limit : usize ,
103- ) -> Result < Vec < PointId > > {
129+ pub fn search ( & self , query : SearchQueryInput ) -> Result < Vec < PointId > > {
104130 // Validate search limit
105- if limit == 0 {
106- return Err ( ApiError :: InvalidSearchLimit { limit } ) ;
131+ if query . limit == 0 {
132+ return Err ( ApiError :: InvalidSearchLimit { limit : query . limit } ) ;
107133 }
108134
109135 // Validate query dimension
110- if query. len ( ) != self . dimension {
136+ if query. vector . len ( ) != self . dimension {
111137 return Err ( ApiError :: DimensionMismatch {
112138 expected : self . dimension ,
113- got : query. len ( ) ,
139+ got : query. vector . len ( ) ,
114140 } ) ;
115141 }
116142
117143 // Use vector index to find similar vectors
118144 let index = self . index . read ( ) . map_err ( |_| ApiError :: LockError ) ?;
119145
120146 //TODO: Add feat of returning similarity scores in the search
121- let vectors = index. search ( query, similarity, limit) ?;
147+ let vectors = index. search ( query. vector , query . similarity , query . limit ) ?;
122148
123149 Ok ( vectors)
124150 }
125151
152+ pub fn search_batch ( & self , queries : Vec < SearchQueryInput > ) -> Result < Vec < Vec < PointId > > > {
153+ let mut results = Vec :: with_capacity ( queries. len ( ) ) ;
154+ let index = self . index . read ( ) . unwrap ( ) ;
155+
156+ for query in queries {
157+ let found = index. search ( query. vector , query. similarity , query. limit ) ?;
158+ results. push ( found) ;
159+ }
160+
161+ Ok ( results)
162+ }
163+
126164 pub fn list ( & self , offset : PointId , limit : usize ) -> Result < Option < VectorPage > > {
127165 let page = self . storage . list_vectors ( offset, limit) ?;
128166 Ok ( page)
@@ -359,7 +397,13 @@ mod tests {
359397
360398 // Search for the closest vector to [1.0, 0.1, 0.1]
361399 let query = vec ! [ 1.0 , 0.1 , 0.1 ] ;
362- let results = db. search ( query, Similarity :: Cosine , 1 ) . unwrap ( ) ;
400+ let results = db
401+ . search ( SearchQueryInput {
402+ vector : query,
403+ similarity : Similarity :: Cosine ,
404+ limit : 1 ,
405+ } )
406+ . unwrap ( ) ;
363407
364408 assert_eq ! ( results. len( ) , 1 ) ;
365409 assert_eq ! ( results[ 0 ] , ids[ 0 ] ) ; // The first vector should be closest
@@ -387,7 +431,13 @@ mod tests {
387431
388432 // Search with limit 3
389433 let query = vec ! [ 0.0 , 0.0 , 0.0 ] ;
390- let results = db. search ( query, Similarity :: Euclidean , 3 ) . unwrap ( ) ;
434+ let results = db
435+ . search ( SearchQueryInput {
436+ vector : query,
437+ similarity : Similarity :: Euclidean ,
438+ limit : 3 ,
439+ } )
440+ . unwrap ( ) ;
391441
392442 assert_eq ! ( results. len( ) , 3 ) ;
393443 }
@@ -397,7 +447,11 @@ mod tests {
397447 let ( db, _temp_dir) = create_test_db ( ) ;
398448
399449 let query = vec ! [ 1.0 , 2.0 , 3.0 ] ;
400- let result = db. search ( query, Similarity :: Cosine , 0 ) ;
450+ let result = db. search ( SearchQueryInput {
451+ vector : query,
452+ similarity : Similarity :: Cosine ,
453+ limit : 0 ,
454+ } ) ;
401455
402456 assert ! ( result. is_err( ) ) ;
403457 match result. unwrap_err ( ) {
@@ -416,7 +470,13 @@ mod tests {
416470 assert ! ( db. get( Uuid :: new_v4( ) ) . unwrap( ) . is_none( ) ) ;
417471
418472 let query = vec ! [ 1.0 , 2.0 , 3.0 ] ;
419- let results = db. search ( query, Similarity :: Cosine , 10 ) . unwrap ( ) ;
473+ let results = db
474+ . search ( SearchQueryInput {
475+ vector : query,
476+ similarity : Similarity :: Cosine ,
477+ limit : 10 ,
478+ } )
479+ . unwrap ( ) ;
420480 assert_eq ! ( results. len( ) , 0 ) ;
421481 }
422482
0 commit comments