@@ -206,6 +206,12 @@ func DefaultConfig(dimensions uint) IndexConfig {
206206 return c
207207}
208208
209+ // FilteredSearchHandler include the callback functiona and user data
210+ type FilteredSearchHandler struct {
211+ Callback func (key Key , handler * FilteredSearchHandler ) int
212+ Data any
213+ }
214+
209215// Index represents a USearch approximate nearest neighbor index.
210216// It implements io.Closer for idiomatic resource cleanup.
211217//
@@ -638,6 +644,56 @@ func (index *Index) Search(query []float32, limit uint) (keys []Key, distances [
638644 return keys , distances , nil
639645}
640646
647+ // Search finds the k nearest neighbors to the query vector.
648+ //
649+ // Parameters:
650+ // - query: Must have exactly Dimensions() elements
651+ // - limit: Maximum number of results to return
652+ //
653+ // Returns:
654+ // - keys: IDs of the nearest vectors (up to limit)
655+ // - distances: Distance to each result (same length as keys)
656+ // - err: Error if query is invalid or search fails
657+ //
658+ // The actual number of results may be less than limit if the index
659+ // contains fewer vectors.
660+ func (index * Index ) FilteredSearch (query []float32 , limit uint , handler * FilteredSearchHandler ) (keys []Key , distances []float32 , err error ) {
661+ if index .handle == nil {
662+ panic ("index is uninitialized" )
663+ }
664+
665+ if len (query ) == 0 {
666+ return nil , nil , errors .New ("query vector cannot be empty" )
667+ }
668+ if uint (len (query )) != index .config .Dimensions {
669+ return nil , nil , fmt .Errorf ("query dimension mismatch: got %d, expected %d" , len (query ), index .config .Dimensions )
670+ }
671+ if handler == nil {
672+ return nil , nil , errors .New ("filtered search handler cannot be nil" )
673+ }
674+ if limit == 0 {
675+ return []Key {}, []float32 {}, nil
676+ }
677+
678+ keys = make ([]Key , limit )
679+ distances = make ([]float32 , limit )
680+ var errorMessage * C.char
681+ resultCount := uint (C .usearch_filtered_search (index .handle , unsafe .Pointer (& query [0 ]), C .usearch_scalar_f32_k , (C .size_t )(limit ),
682+ (C .usearch_filtered_search_callback_t )(C .goFilteredSearchCallback ), unsafe .Pointer (handler ),
683+ (* C .usearch_key_t )(& keys [0 ]), (* C .usearch_distance_t )(& distances [0 ]), (* C .usearch_error_t )(& errorMessage )))
684+ runtime .KeepAlive (query )
685+ runtime .KeepAlive (keys )
686+ runtime .KeepAlive (distances )
687+ runtime .KeepAlive (handler )
688+ if errorMessage != nil {
689+ return nil , nil , errors .New (C .GoString (errorMessage ))
690+ }
691+
692+ keys = keys [:resultCount ]
693+ distances = distances [:resultCount ]
694+ return keys , distances , nil
695+ }
696+
641697// SearchUnsafe performs k-Approximate Nearest Neighbors Search using an unsafe pointer.
642698//
643699// SAFETY REQUIREMENTS:
@@ -675,6 +731,48 @@ func (index *Index) SearchUnsafe(query unsafe.Pointer, limit uint) (keys []Key,
675731 return keys , distances , nil
676732}
677733
734+ //export goFilteredSearchCallback
735+ func goFilteredSearchCallback (key C.usearch_key_t , ptr unsafe.Pointer ) C.int {
736+ handler := (* FilteredSearchHandler )(ptr )
737+ return C .int (handler .Callback (Key (key ), handler ))
738+ }
739+
740+ // Filtred Search performs k-Approximate Nearest Neighbors Search for the closest vectors to the query vector with filtering.
741+ func (index * Index ) FilteredSearchUnsafe (query unsafe.Pointer , limit uint , handler * FilteredSearchHandler ) (keys []Key , distances []float32 , err error ) {
742+ if index .handle == nil {
743+ panic ("index is uninitialized" )
744+ }
745+
746+ if query == nil {
747+ return nil , nil , errors .New ("query pointer cannot be nil" )
748+ }
749+
750+ if handler == nil {
751+ return nil , nil , errors .New ("filtered search handler cannot be nil" )
752+ }
753+
754+ if limit == 0 {
755+ return []Key {}, []float32 {}, nil
756+ }
757+
758+ keys = make ([]Key , limit )
759+ distances = make ([]float32 , limit )
760+ var errorMessage * C.char
761+ resultCount := uint (C .usearch_filtered_search (index .handle , query , index .config .Quantization .CValue (), (C .size_t )(limit ),
762+ (C .usearch_filtered_search_callback_t )(C .goFilteredSearchCallback ), unsafe .Pointer (handler ),
763+ (* C .usearch_key_t )(& keys [0 ]), (* C .usearch_distance_t )(& distances [0 ]), (* C .usearch_error_t )(& errorMessage )))
764+ runtime .KeepAlive (keys )
765+ runtime .KeepAlive (distances )
766+ runtime .KeepAlive (handler )
767+ if errorMessage != nil {
768+ return nil , nil , errors .New (C .GoString (errorMessage ))
769+ }
770+
771+ keys = keys [:resultCount ]
772+ distances = distances [:resultCount ]
773+ return keys , distances , nil
774+ }
775+
678776// ExactSearch performs multithreaded exact nearest neighbors search.
679777// Unlike the index-based search, this computes distances to all vectors in the dataset.
680778//
@@ -823,6 +921,43 @@ func (index *Index) SearchI8(query []int8, limit uint) (keys []Key, distances []
823921 return keys , distances , nil
824922}
825923
924+ func (index * Index ) FilteredSearchI8 (query []int8 , limit uint , handler * FilteredSearchHandler ) (keys []Key , distances []float32 , err error ) {
925+ if index .handle == nil {
926+ panic ("index is uninitialized" )
927+ }
928+
929+ if len (query ) == 0 {
930+ return nil , nil , errors .New ("query vector cannot be empty" )
931+ }
932+ if uint (len (query )) != index .config .Dimensions {
933+ return nil , nil , fmt .Errorf ("query dimension mismatch: got %d, expected %d" , len (query ), index .config .Dimensions )
934+ }
935+ if handler == nil {
936+ return nil , nil , errors .New ("filtered search handler cannot be nil" )
937+ }
938+ if limit == 0 {
939+ return []Key {}, []float32 {}, nil
940+ }
941+
942+ keys = make ([]Key , limit )
943+ distances = make ([]float32 , limit )
944+ var errorMessage * C.char
945+ resultCount := uint (C .usearch_filtered_search (index .handle , unsafe .Pointer (& query [0 ]), C .usearch_scalar_i8_k , (C .size_t )(limit ),
946+ (C .usearch_filtered_search_callback_t )(C .goFilteredSearchCallback ), unsafe .Pointer (handler ),
947+ (* C .usearch_key_t )(& keys [0 ]), (* C .usearch_distance_t )(& distances [0 ]), (* C .usearch_error_t )(& errorMessage )))
948+ runtime .KeepAlive (query )
949+ runtime .KeepAlive (keys )
950+ runtime .KeepAlive (distances )
951+ runtime .KeepAlive (handler )
952+ if errorMessage != nil {
953+ return nil , nil , errors .New (C .GoString (errorMessage ))
954+ }
955+
956+ keys = keys [:resultCount ]
957+ distances = distances [:resultCount ]
958+ return keys , distances , nil
959+ }
960+
826961// DistanceI8 computes the distance between two int8 vectors.
827962//
828963// Example:
0 commit comments