Skip to content
Snippets Groups Projects
Unverified Commit 9030854e authored by Cai Yudong's avatar Cai Yudong Committed by GitHub
Browse files

Support range search for HNSW (#189)


Signed-off-by: default avataryudong.cai <yudong.cai@zilliz.com>
parent 930235a9
No related branches found
Tags v1.1.8
No related merge requests found
......@@ -74,8 +74,8 @@ IndexHNSW::Load(const BinarySet& index_binary) {
hnsw_stats->update_level_distribution(index_->maxlevel_, index_->level_stats_);
}
#endif
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Load finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << hnsw_stats->ToString();
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Load finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << hnsw_stats->ToString();
} catch (std::exception& e) {
KNOWHERE_THROW_MSG(e.what());
}
......@@ -123,8 +123,8 @@ IndexHNSW::AddWithoutIds(const DatasetPtr& dataset_ptr, const Config& config) {
hnsw_stats->update_level_distribution(index_->maxlevel_, index_->level_stats_);
}
#endif
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Train finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << GetStatistics()->ToString();
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Train finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << GetStatistics()->ToString();
}
DatasetPtr
......@@ -209,12 +209,61 @@ IndexHNSW::Query(const DatasetPtr& dataset_ptr, const Config& config, const fais
}
}
#endif
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Query finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << GetStatistics()->ToString();
// LOG_KNOWHERE_DEBUG_ << "IndexHNSW::Query finished, show statistics:";
// LOG_KNOWHERE_DEBUG_ << GetStatistics()->ToString();
return GenResultDataset(p_id, p_dist);
}
DatasetPtr
IndexHNSW::QueryByRange(const DatasetPtr& dataset,
const Config& config,
const faiss::BitsetView bitset) {
if (!index_) {
KNOWHERE_THROW_MSG("index not initialize or trained");
}
GET_TENSOR_DATA_DIM(dataset)
auto range_k = GetIndexParamHNSWK(config);
auto radius = GetMetaRadius(config);
index_->setEf(GetIndexParamEf(config));
bool is_IP = (index_->metric_type_ == 1); // InnerProduct: 1
std::vector<std::vector<int64_t>> result_id_array(rows);
std::vector<std::vector<float>> result_dist_array(rows);
std::vector<size_t> result_lims(rows + 1, 0);
//#pragma omp parallel for
for (unsigned int i = 0; i < rows; ++i) {
auto single_query = (float*)p_data + i * dim;
auto dummy_stat = hnswlib::StatisticsInfo();
auto rst = index_->searchRange(single_query, range_k, (is_IP ? 1.0f - radius : radius), bitset, dummy_stat);
for (auto& p : rst) {
result_dist_array[i].push_back(is_IP ? (1 - p.first) : p.first);
result_id_array[i].push_back(p.second);
}
result_lims[i+1] = result_lims[i] + rst.size();
}
LOG_KNOWHERE_DEBUG_ << "Range search result num: " << result_lims.back();
auto p_id = static_cast<int64_t*>(malloc(result_lims.back() * sizeof(int64_t)));
auto p_dist = static_cast<float*>(malloc(result_lims.back() * sizeof(float)));
auto p_lims = static_cast<size_t*>(malloc((rows + 1) * sizeof(size_t)));
for (int64_t i = 0; i < rows; i++) {
size_t start = result_lims[i];
size_t size = result_lims[i+1] - result_lims[i];
memcpy(p_id + start, result_id_array[i].data(), size * sizeof(int64_t));
memcpy(p_dist + start, result_dist_array[i].data(), size * sizeof(float));
}
memcpy(p_lims, result_lims.data(), (rows + 1) * sizeof(size_t));
return GenResultDataset(p_id, p_dist, p_lims);
}
int64_t
IndexHNSW::Count() {
if (!index_) {
......
......@@ -28,19 +28,22 @@ class IndexHNSW : public VecIndex {
}
BinarySet
Serialize(const Config& config) override;
Serialize(const Config&) override;
void
Load(const BinarySet& index_binary) override;
Load(const BinarySet&) override;
void
Train(const DatasetPtr& dataset_ptr, const Config& config) override;
Train(const DatasetPtr&, const Config&) override;
void
AddWithoutIds(const DatasetPtr&, const Config&) override;
DatasetPtr
Query(const DatasetPtr& dataset_ptr, const Config& config, const faiss::BitsetView bitset) override;
Query(const DatasetPtr&, const Config&, const faiss::BitsetView) override;
DatasetPtr
QueryByRange(const DatasetPtr&, const Config&, const faiss::BitsetView) override;
int64_t
Count() override;
......
......@@ -50,13 +50,13 @@ DEFINE_DATASET_SETTER(SetDatasetLims, meta::LIMS, const size_t*);
///////////////////////////////////////////////////////////////////////////////
#define GET_TENSOR_DATA(ds_ptr) \
auto rows = GetDatasetRows(ds_ptr); \
auto p_data = GetDatasetTensor(ds_ptr);
#define GET_TENSOR_DATA(ds_ptr) \
auto rows = knowhere::GetDatasetRows(ds_ptr); \
auto p_data = knowhere::GetDatasetTensor(ds_ptr);
#define GET_TENSOR_DATA_DIM(ds_ptr) \
GET_TENSOR_DATA(ds_ptr) \
auto dim = GetDatasetDim(ds_ptr);
#define GET_TENSOR_DATA_DIM(ds_ptr) \
GET_TENSOR_DATA(ds_ptr) \
auto dim = knowhere::GetDatasetDim(ds_ptr);
extern DatasetPtr
GenDataset(const int64_t nb, const int64_t dim, const void* xb);
......
......@@ -46,6 +46,7 @@ constexpr IndexParamType PQ_M = "PQM"; // PQ param for RHNSWPQ
constexpr IndexParamType EFCONSTRUCTION = "efConstruction";
constexpr IndexParamType HNSW_M = "M";
constexpr IndexParamType EF = "ef";
constexpr IndexParamType HNSW_K = "range_k";
// Annoy Params
constexpr IndexParamType N_TREES = "n_trees";
constexpr IndexParamType SEARCH_K = "search_k";
......@@ -157,6 +158,9 @@ DEFINE_CONFIG_SETTER(SetIndexParamHNSWM, indexparam::HNSW_M, int64_t, int64_t)
DEFINE_CONFIG_GETTER(GetIndexParamEf, indexparam::EF, int64_t)
DEFINE_CONFIG_SETTER(SetIndexParamEf, indexparam::EF, int64_t, int64_t)
DEFINE_CONFIG_GETTER(GetIndexParamHNSWK, indexparam::HNSW_K, int64_t)
DEFINE_CONFIG_SETTER(SetIndexParamHNSWK, indexparam::HNSW_K, int64_t, int64_t)
// Annoy Params
DEFINE_CONFIG_GETTER(GetIndexParamNtrees, indexparam::N_TREES, int64_t)
DEFINE_CONFIG_SETTER(SetIndexParamNtrees, indexparam::N_TREES, int64_t, int64_t)
......
......@@ -379,6 +379,68 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
return return_list;
}
std::vector<std::pair<dist_t, labeltype>>
getNeighboursWithinRadius(std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>,
CompareByFirst>& top_candidates,
const void* data_point, float radius, const faiss::BitsetView bitset) const {
std::vector<std::pair<dist_t, labeltype>> result;
VisitedList* vl = visited_list_pool_->getFreeVisitedList();
vl_type* visited_array = vl->mass;
vl_type visited_array_tag = vl->curV;
std::queue<std::pair<dist_t, tableint>> radius_queue;
while (!top_candidates.empty()) {
auto cand = top_candidates.top();
top_candidates.pop();
if (cand.first < radius) {
radius_queue.push(cand);
result.emplace_back(cand.first, cand.second);
}
visited_array[cand.second] = visited_array_tag;
}
while (!radius_queue.empty()) {
auto cur = radius_queue.front();
radius_queue.pop();
tableint current_id = cur.second;
int* data = (int*)get_linklist0(current_id);
size_t size = getListCount((linklistsizeint*)data);
#ifdef USE_SSE
_mm_prefetch((char*)(visited_array + *(data + 1)), _MM_HINT_T0);
_mm_prefetch((char*)(visited_array + *(data + 1) + 64), _MM_HINT_T0);
_mm_prefetch(data_level0_memory_ + (*(data + 1)) * size_data_per_element_ + offsetData_, _MM_HINT_T0);
_mm_prefetch((char*)(data + 2), _MM_HINT_T0);
#endif
for (size_t j = 1; j <= size; j++) {
int candidate_id = *(data + j);
#ifdef USE_SSE
_mm_prefetch((char*)(visited_array + *(data + j + 1)), _MM_HINT_T0);
_mm_prefetch(data_level0_memory_ + (*(data + j + 1)) * size_data_per_element_ + offsetData_,
_MM_HINT_T0); ////////////
#endif
if (!(visited_array[candidate_id] == visited_array_tag)) {
visited_array[candidate_id] = visited_array_tag;
if (bitset.empty() || !bitset.test((int64_t)candidate_id)) {
char* cand_obj = (getDataByInternalId(candidate_id));
dist_t dist = fstdistfunc_(data_point, cand_obj, dist_func_param_);
if (dist < radius) {
radius_queue.push({dist, candidate_id});
result.emplace_back(dist, candidate_id);
}
}
}
}
}
visited_list_pool_->releaseVisitedList(vl);
return result;
}
linklistsizeint*
get_linklist0(tableint internal_id) const {
return (linklistsizeint*)(data_level0_memory_ + internal_id * size_data_per_element_ + offsetLevel0_);
......@@ -1106,6 +1168,62 @@ class HierarchicalNSW : public AlgorithmInterface<dist_t> {
return result;
};
std::vector<std::pair<dist_t, labeltype>>
searchRange(const void* query_data, size_t range_k, float radius, const faiss::BitsetView bitset,
StatisticsInfo& stats) const {
if (cur_element_count == 0) {
return {};
}
tableint currObj = enterpoint_node_;
dist_t curdist = fstdistfunc_(query_data, getDataByInternalId(enterpoint_node_), dist_func_param_);
for (int level = maxlevel_; level > 0; level--) {
bool changed = true;
while (changed) {
changed = false;
unsigned int* data;
data = (unsigned int*)get_linklist(currObj, level);
int size = getListCount(data);
metric_hops++;
metric_distance_computations += size;
tableint* datal = (tableint*)(data + 1);
for (int i = 0; i < size; i++) {
tableint cand = datal[i];
if (cand < 0 || cand > max_elements_)
throw std::runtime_error("cand error");
dist_t d = fstdistfunc_(query_data, getDataByInternalId(cand), dist_func_param_);
if (d < curdist) {
curdist = d;
currObj = cand;
changed = true;
}
}
}
}
std::priority_queue<std::pair<dist_t, tableint>, std::vector<std::pair<dist_t, tableint>>, CompareByFirst>
top_candidates;
if (!bitset.empty()) {
top_candidates = searchBaseLayerST<true, true>(currObj, query_data, std::max(ef_, range_k), bitset, stats);
} else {
top_candidates = searchBaseLayerST<false, true>(currObj, query_data, std::max(ef_, range_k), bitset, stats);
}
while (top_candidates.size() > range_k) {
top_candidates.pop();
}
if (top_candidates.size() == 0) {
return {};
}
return getNeighboursWithinRadius(top_candidates, query_data, radius, bitset);
}
void
checkIntegrity() {
int connections_checked = 0;
......
......@@ -183,6 +183,9 @@ class AlgorithmInterface {
virtual std::priority_queue<std::pair<dist_t, labeltype >>
searchKnn(const void *, size_t, const faiss::BitsetView, hnswlib::StatisticsInfo&) const = 0;
virtual std::vector<std::pair<dist_t, labeltype>>
searchRange(const void*, size_t, float, const faiss::BitsetView, hnswlib::StatisticsInfo&) const = 0;
// Return k nearest neighbor in the order of closer fist
virtual std::vector<std::pair<dist_t, labeltype>>
searchKnnCloserFirst(const void* query_data, size_t k, const faiss::BitsetView, hnswlib::StatisticsInfo&) const;
......
......@@ -95,11 +95,20 @@ class ParamGenerator {
{knowhere::indexparam::EF, 200},
{knowhere::INDEX_FILE_SLICE_SIZE_IN_MEGABYTE, knowhere::index_file_slice_size},
};
} else if (type == knowhere::IndexEnum::INDEX_HNSW) {
return knowhere::Config {
{knowhere::meta::METRIC_TYPE, knowhere::metric::L2},
{knowhere::meta::DIM, DIM},
{knowhere::meta::TOPK, K},
{knowhere::indexparam::HNSW_M, 16},
{knowhere::indexparam::EFCONSTRUCTION, 200},
{knowhere::indexparam::EF, 200},
};
} else if (type == knowhere::IndexEnum::INDEX_RHNSWFlat) {
return knowhere::Config{
{knowhere::meta::METRIC_TYPE, knowhere::metric::L2},
{knowhere::meta::DIM, 64},
{knowhere::meta::TOPK, 10},
{knowhere::meta::DIM, DIM},
{knowhere::meta::TOPK, K},
{knowhere::indexparam::HNSW_M, 16},
{knowhere::indexparam::EFCONSTRUCTION, 200},
{knowhere::indexparam::EF, 200},
......@@ -108,8 +117,8 @@ class ParamGenerator {
} else if (type == knowhere::IndexEnum::INDEX_RHNSWPQ) {
return knowhere::Config{
{knowhere::meta::METRIC_TYPE, knowhere::metric::L2},
{knowhere::meta::DIM, 64},
{knowhere::meta::TOPK, 10},
{knowhere::meta::DIM, DIM},
{knowhere::meta::TOPK, K},
{knowhere::indexparam::HNSW_M, 16},
{knowhere::indexparam::EFCONSTRUCTION, 200},
{knowhere::indexparam::EF, 200},
......@@ -119,8 +128,8 @@ class ParamGenerator {
} else if (type == knowhere::IndexEnum::INDEX_RHNSWSQ) {
return knowhere::Config{
{knowhere::meta::METRIC_TYPE, knowhere::metric::L2},
{knowhere::meta::DIM, 64},
{knowhere::meta::TOPK, 10},
{knowhere::meta::DIM, DIM},
{knowhere::meta::TOPK, K},
{knowhere::indexparam::HNSW_M, 16},
{knowhere::indexparam::EFCONSTRUCTION, 200},
{knowhere::indexparam::EF, 200},
......
......@@ -10,15 +10,16 @@
// or implied. See the License for the specific language governing permissions and limitations under the License.
#include <gtest/gtest.h>
#include <iostream>
#include <random>
#include "knowhere/common/Config.h"
#include "knowhere/common/Exception.h"
#include "knowhere/index/vector_index/ConfAdapterMgr.h"
#include "knowhere/index/vector_index/IndexHNSW.h"
#include "knowhere/index/vector_index/adapter/VectorAdapter.h"
#include "knowhere/index/vector_index/helpers/IndexParameter.h"
#include "knowhere/utils/distances_simd.h"
#include "unittest/Helper.h"
#include "unittest/range_utils.h"
#include "unittest/utils.h"
using ::testing::Combine;
......@@ -29,17 +30,13 @@ class HNSWTest : public DataGen, public TestWithParam<std::string> {
protected:
void
SetUp() override {
Generate(64, 10000, 10); // dim = 64, nb = 10000, nq = 10
Init_with_default();
conf_ = ParamGenerator::GetInstance().Gen(index_type_);
index_ = std::make_shared<knowhere::IndexHNSW>();
conf = knowhere::Config{
{knowhere::meta::DIM, 64}, {knowhere::meta::TOPK, 10},
{knowhere::indexparam::HNSW_M, 16}, {knowhere::indexparam::EFCONSTRUCTION, 200},
{knowhere::indexparam::EF, 200}, {knowhere::meta::METRIC_TYPE, knowhere::metric::L2},
};
}
protected:
knowhere::Config conf;
knowhere::Config conf_;
knowhere::IndexMode index_mode_ = knowhere::IndexMode::MODE_CPU;
knowhere::IndexType index_type_ = knowhere::IndexEnum::INDEX_HNSW;
std::shared_ptr<knowhere::IndexHNSW> index_ = nullptr;
......@@ -54,45 +51,44 @@ TEST_P(HNSWTest, HNSW_basic) {
/*
{
ASSERT_ANY_THROW(index_->Serialize());
ASSERT_ANY_THROW(index_->Query(query_dataset, conf));
ASSERT_ANY_THROW(index_->AddWithoutIds(nullptr, conf));
ASSERT_ANY_THROW(index_->Query(query_dataset, conf_));
ASSERT_ANY_THROW(index_->AddWithoutIds(nullptr, conf_));
ASSERT_ANY_THROW(index_->Count());
ASSERT_ANY_THROW(index_->Dim());
}
*/
index_->Train(base_dataset, conf);
index_->AddWithoutIds(base_dataset, conf);
index_->BuildAll(base_dataset, conf_);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
ASSERT_GT(index_->Size(), 0);
// Serialize and Load before Query
knowhere::BinarySet bs = index_->Serialize(conf);
GET_TENSOR_DATA(base_dataset)
int64_t dim = knowhere::GetDatasetDim(base_dataset);
int64_t rows = knowhere::GetDatasetRows(base_dataset);
auto raw_data = knowhere::GetDatasetTensor(base_dataset);
// Serialize and Load before Query
knowhere::BinarySet bs = index_->Serialize(conf_);
knowhere::BinaryPtr bptr = std::make_shared<knowhere::Binary>();
bptr->data = std::shared_ptr<uint8_t[]>((uint8_t*)raw_data, [&](uint8_t*) {});
bptr->data = std::shared_ptr<uint8_t[]>((uint8_t*)p_data, [&](uint8_t*) {});
bptr->size = dim * rows * sizeof(float);
bs.Append(RAW_DATA, bptr);
index_->Load(bs);
auto adapter = knowhere::AdapterMgr::GetInstance().GetAdapter(index_type_);
ASSERT_TRUE(adapter->CheckSearch(conf, index_type_, index_mode_));
ASSERT_TRUE(adapter->CheckSearch(conf_, index_type_, index_mode_));
auto result = index_->Query(query_dataset, conf, nullptr);
auto result = index_->Query(query_dataset, conf_, nullptr);
AssertAnns(result, nq, k);
auto result2 = index_->Query(query_dataset, conf_, *bitset);
AssertAnns(result2, nq, k, CheckMode::CHECK_NOT_EQUAL);
// case: k > nb
const int64_t new_rows = 6;
knowhere::SetDatasetRows(base_dataset, new_rows);
index_->Train(base_dataset, conf);
index_->AddWithoutIds(base_dataset, conf);
auto result2 = index_->Query(query_dataset, conf, nullptr);
auto res_ids = knowhere::GetDatasetIDs(result2);
index_->BuildAll(base_dataset, conf_);
auto result3 = index_->Query(query_dataset, conf_, nullptr);
auto res_ids = knowhere::GetDatasetIDs(result3);
for (int64_t i = 0; i < nq; i++) {
for (int64_t j = new_rows; j < k; j++) {
ASSERT_EQ(res_ids[i * k + j], -1);
......@@ -100,64 +96,81 @@ TEST_P(HNSWTest, HNSW_basic) {
}
}
TEST_P(HNSWTest, HNSW_delete) {
assert(!xb.empty());
TEST_P(HNSWTest, HNSW_serialize) {
auto serialize = [](const std::string& filename, knowhere::BinaryPtr& bin, uint8_t* ret) {
{
FileIOWriter writer(filename);
writer(static_cast<void*>(bin->data.get()), bin->size);
}
FileIOReader reader(filename);
reader(ret, bin->size);
};
index_->BuildAll(base_dataset, conf_);
auto binaryset = index_->Serialize(conf_);
auto bin = binaryset.GetByName("HNSW");
std::string filename = temp_path("/tmp/HNSW_test_serialize.bin");
auto load_data = new uint8_t[bin->size];
serialize(filename, bin, load_data);
index_->Train(base_dataset, conf);
index_->AddWithoutIds(base_dataset, conf);
binaryset.clear();
std::shared_ptr<uint8_t[]> data(load_data);
binaryset.Append("HNSW", data, bin->size);
index_->Load(binaryset);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
auto result = index_->Query(query_dataset, conf_, nullptr);
AssertAnns(result, nq, k);
}
// Serialize and Load before Query
knowhere::BinarySet bs = index_->Serialize(conf);
TEST_P(HNSWTest, hnsw_range_search_l2) {
knowhere::SetMetaMetricType(conf_, knowhere::metric::L2);
knowhere::SetIndexParamHNSWK(conf_, 20);
int64_t dim = knowhere::GetDatasetDim(base_dataset);
int64_t rows = knowhere::GetDatasetRows(base_dataset);
auto raw_data = knowhere::GetDatasetTensor(base_dataset);
knowhere::BinaryPtr bptr = std::make_shared<knowhere::Binary>();
bptr->data = std::shared_ptr<uint8_t[]>((uint8_t*)raw_data, [&](uint8_t*) {});
bptr->size = dim * rows * sizeof(float);
bs.Append(RAW_DATA, bptr);
index_->BuildAll(base_dataset, conf_);
index_->Load(bs);
auto qd = knowhere::GenDataset(nq, dim, xq.data());
auto result1 = index_->Query(query_dataset, conf, nullptr);
AssertAnns(result1, nq, k);
auto test_range_search_l2 = [&](float radius, const faiss::BitsetView bitset) {
std::vector<int64_t> golden_labels;
std::vector<size_t> golden_lims;
RunRangeSearchBF<CMin<float>>(golden_labels, golden_lims, xb, nb, xq, nq, dim,
radius * radius, faiss::fvec_L2sqr_ref, bitset);
auto result2 = index_->Query(query_dataset, conf, *bitset);
AssertAnns(result2, nq, k, CheckMode::CHECK_NOT_EQUAL);
auto result = index_->QueryByRange(qd, conf_, bitset);
CheckRangeSearchResult<CMin<float>>(result, nq, radius * radius, golden_labels, golden_lims, false);
};
for (float radius: {4.1f, 4.2f, 4.3f}) {
knowhere::SetMetaRadius(conf_, radius);
test_range_search_l2(radius, nullptr);
test_range_search_l2(radius, *bitset);
}
}
/*
TEST_P(HNSWTest, HNSW_serialize) {
auto serialize = [](const std::string& filename, knowhere::BinaryPtr& bin, uint8_t* ret) {
{
FileIOWriter writer(filename);
writer(static_cast<void*>(bin->data.get()), bin->size);
}
TEST_P(HNSWTest, hnsw_range_search_ip) {
knowhere::SetMetaMetricType(conf_, knowhere::metric::IP);
knowhere::SetIndexParamHNSWK(conf_, 20);
FileIOReader reader(filename);
reader(ret, bin->size);
index_->BuildAll(base_dataset, conf_);
auto qd = knowhere::GenDataset(nq, dim, xq.data());
auto test_range_search_ip = [&](float radius, const faiss::BitsetView bitset) {
std::vector<int64_t> golden_labels;
std::vector<size_t> golden_lims;
RunRangeSearchBF<CMax<float>>(golden_labels, golden_lims, xb, nb, xq, nq, dim,
radius, faiss::fvec_inner_product_ref, bitset);
auto result = index_->QueryByRange(qd, conf_, bitset);
CheckRangeSearchResult<CMax<float>>(result, nq, radius, golden_labels, golden_lims, false);
};
{
index_->Train(base_dataset, conf);
index_->AddWithoutIds(base_dataset, conf);
auto binaryset = index_->Serialize();
auto bin = binaryset.GetByName("HNSW");
std::string filename = temp_path("/tmp/HNSW_test_serialize.bin");
auto load_data = new uint8_t[bin->size];
serialize(filename, bin, load_data);
binaryset.clear();
std::shared_ptr<uint8_t[]> data(load_data);
binaryset.Append("HNSW", data, bin->size);
index_->Load(binaryset);
EXPECT_EQ(index_->Count(), nb);
EXPECT_EQ(index_->Dim(), dim);
auto result = index_->Query(query_dataset, conf);
AssertAnns(result, nq, conf[knowhere::meta::TOPK]);
for (float radius: {42.0f, 43.0f, 44.0f}) {
knowhere::SetMetaRadius(conf_, radius);
test_range_search_ip(radius, nullptr);
test_range_search_ip(radius, *bitset);
}
}*/
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment