@@ -12,21 +12,21 @@ unsigned char BF_BatchIterator::next_id = 0;
1212
1313// heuristics: decide if using heap or select search, based on the ratio between the
1414// number of remaining results and the index size.
15- VecSimQueryResult * BF_BatchIterator::searchByHeuristics (size_t n_res,
16- VecSimQueryResult_Order order) {
15+ VecSimQueryResult_List BF_BatchIterator::searchByHeuristics (size_t n_res,
16+ VecSimQueryResult_Order order) {
1717 if ((this ->index ->indexSize () - this ->getResultsCount ()) / 1000 > n_res) {
1818 // Heap based search always returns the results ordered by score
1919 return this ->heapBasedSearch (n_res);
2020 }
21- VecSimQueryResult *res = this ->selectBasedSearch (n_res);
21+ VecSimQueryResult_List rl = this ->selectBasedSearch (n_res);
2222 if (order == BY_SCORE) {
23- sort_results_by_score (res );
23+ sort_results_by_score (rl );
2424 }
25- return res ;
25+ return rl ;
2626}
2727
28- void BF_BatchIterator::swapScores (const unordered_map< size_t , size_t > &TopCandidatesIndices,
29- size_t res_num) {
28+ void BF_BatchIterator::swapScores (
29+ const vecsim_stl::unordered_map< size_t , size_t > &TopCandidatesIndices, size_t res_num) {
3030 // Create a set of the indices in the scores array for every results that we return.
3131 set<size_t > indices;
3232 for (auto pos : TopCandidatesIndices) {
@@ -55,11 +55,12 @@ void BF_BatchIterator::swapScores(const unordered_map<size_t, size_t> &TopCandid
5555 this ->scores_valid_start_pos = next_scores_valid_start_pos;
5656}
5757
58- VecSimQueryResult *BF_BatchIterator::heapBasedSearch (size_t n_res) {
58+ VecSimQueryResult_List BF_BatchIterator::heapBasedSearch (size_t n_res) {
59+ VecSimQueryResult_List rl = {0 };
5960 float upperBound = std::numeric_limits<float >::lowest ();
6061 vecsim_stl::max_priority_queue<pair<float , labelType>> TopCandidates (this ->allocator );
6162 // map vector's label to its index in the scores vector.
62- unordered_map<size_t , size_t > TopCandidatesIndices (n_res);
63+ vecsim_stl:: unordered_map<size_t , size_t > TopCandidatesIndices (n_res, this -> allocator );
6364 for (size_t i = this ->scores_valid_start_pos ; i < this ->scores .size (); i++) {
6465 if (TopCandidates.size () < n_res) {
6566 TopCandidates.emplace (this ->scores [i].first , this ->scores [i].second );
@@ -69,28 +70,30 @@ VecSimQueryResult *BF_BatchIterator::heapBasedSearch(size_t n_res) {
6970 if (this ->scores [i].first >= upperBound) {
7071 continue ;
7172 } else {
72- TopCandidates.emplace (this ->scores [i].first , this ->scores [i].second );
73- TopCandidatesIndices[this ->scores [i].second ] = i;
7473 // remove the furthest vector from the candidates and from the label->index mappings
74+ // we first remove the worst candidate so we wont exceed the allocated size
7575 TopCandidatesIndices.erase (TopCandidates.top ().second );
7676 TopCandidates.pop ();
77+ TopCandidatesIndices[this ->scores [i].second ] = i;
78+ TopCandidates.emplace (this ->scores [i].first , this ->scores [i].second );
7779 upperBound = TopCandidates.top ().first ;
7880 }
7981 }
8082 }
8183
8284 // Save the top results to return.
83- auto * results = array_new_len<VecSimQueryResult>(TopCandidates.size (), TopCandidates.size ());
85+ rl. results = array_new_len<VecSimQueryResult>(TopCandidates.size (), TopCandidates.size ());
8486 for (int i = (int )TopCandidates.size () - 1 ; i >= 0 ; --i) {
85- VecSimQueryResult_SetId (results[i], TopCandidates.top ().second );
86- VecSimQueryResult_SetScore (results[i], TopCandidates.top ().first );
87+ VecSimQueryResult_SetId (rl. results [i], TopCandidates.top ().second );
88+ VecSimQueryResult_SetScore (rl. results [i], TopCandidates.top ().first );
8789 TopCandidates.pop ();
8890 }
89- swapScores (TopCandidatesIndices, array_len (results));
90- return results ;
91+ swapScores (TopCandidatesIndices, array_len (rl. results ));
92+ return rl ;
9193}
9294
93- VecSimQueryResult *BF_BatchIterator::selectBasedSearch (size_t n_res) {
95+ VecSimQueryResult_List BF_BatchIterator::selectBasedSearch (size_t n_res) {
96+ VecSimQueryResult_List rl = {0 };
9497 size_t remaining_vectors_count = this ->scores .size () - this ->scores_valid_start_pos ;
9598 // Get an iterator to the effective first element in the scores array, which is the first
9699 // element that hasn't been returned in previous iterations.
@@ -105,20 +108,22 @@ VecSimQueryResult *BF_BatchIterator::selectBasedSearch(size_t n_res) {
105108 // will be placed before it, and all the rest will be placed after.
106109 std::nth_element (valid_begin_it, n_th_element_pos, this ->scores .end ());
107110
108- auto * results = array_new<VecSimQueryResult>(n_res);
111+ rl. results = array_new<VecSimQueryResult>(n_res);
109112 for (size_t i = this ->scores_valid_start_pos ; i < this ->scores_valid_start_pos + n_res; i++) {
110- results = array_append (results, VecSimQueryResult{});
111- VecSimQueryResult_SetId (results[array_len (results) - 1 ], this ->scores [i].second );
112- VecSimQueryResult_SetScore (results[array_len (results) - 1 ], this ->scores [i].first );
113+ rl. results = array_append (rl. results , VecSimQueryResult{});
114+ VecSimQueryResult_SetId (rl. results [array_len (rl. results ) - 1 ], this ->scores [i].second );
115+ VecSimQueryResult_SetScore (rl. results [array_len (rl. results ) - 1 ], this ->scores [i].first );
113116 }
114117 // Update the valid results start position after returning the results.
115- this ->scores_valid_start_pos += array_len (results);
116- return results ;
118+ this ->scores_valid_start_pos += array_len (rl. results );
119+ return rl ;
117120}
118121
119122BF_BatchIterator::BF_BatchIterator (void *query_vector, const BruteForceIndex *bf_index,
123+ VecSimQueryParams *queryParams,
120124 std::shared_ptr<VecSimAllocator> allocator)
121- : VecSimBatchIterator(query_vector, allocator), index(bf_index), scores_valid_start_pos(0 ) {
125+ : VecSimBatchIterator(query_vector, queryParams ? queryParams->timeoutCtx : nullptr , allocator),
126+ index(bf_index), scores_valid_start_pos(0 ) {
122127 BF_BatchIterator::next_id++;
123128}
124129
@@ -131,20 +136,29 @@ VecSimQueryResult_List BF_BatchIterator::getNextResults(size_t n_res,
131136 assert (getResultsCount () == 0 );
132137 this ->scores .reserve (this ->index ->indexSize ());
133138 vecsim_stl::vector<VectorBlock *> blocks = this ->index ->getVectorBlocks ();
139+ VecSimQueryResult_Code rc;
134140 for (auto &block : blocks) {
135141 // compute the scores for the vectors in every block and extend the scores array.
136- vecsim_stl::vector<std::pair<float , labelType>> block_scores =
137- block->computeBlockScores (getIndex ()->distFunc (), getQueryBlob ());
138- this ->scores .insert (this ->scores .end (), block_scores.begin (), block_scores.end ());
142+ auto block_scores = this ->index ->computeBlockScores (block, this ->getQueryBlob (),
143+ this ->getTimeoutCtx (), &rc);
144+ if (VecSim_OK != rc) {
145+ return {NULL , rc};
146+ }
147+ for (size_t i = 0 ; i < block_scores.size (); i++) {
148+ this ->scores .emplace_back (block_scores[i], block->getMember (i)->label );
149+ }
139150 }
140151 }
141- VecSimQueryResult *results = searchByHeuristics (n_res, order);
152+ if (__builtin_expect (VecSimIndex::timeoutCallback (this ->getTimeoutCtx ()), 0 )) {
153+ return {NULL , VecSim_QueryResult_TimedOut};
154+ }
155+ VecSimQueryResult_List rl = searchByHeuristics (n_res, order);
142156
143- this ->updateResultsCount (array_len (results));
157+ this ->updateResultsCount (array_len (rl. results ));
144158 if (order == BY_ID) {
145- sort_results_by_id (results );
159+ sort_results_by_id (rl );
146160 }
147- return results ;
161+ return rl ;
148162}
149163
150164bool BF_BatchIterator::isDepleted () {
0 commit comments