diff --git a/include/knowhere/config.h b/include/knowhere/config.h index 811f95378..208d1ce31 100644 --- a/include/knowhere/config.h +++ b/include/knowhere/config.h @@ -501,6 +501,7 @@ const float defaultRangeFilter = 1.0f / 0.0; class BaseConfig : public Config { public: + CFG_INT dim; // just used for config verify CFG_STRING metric_type; CFG_INT k; CFG_INT num_build_thread; @@ -535,6 +536,7 @@ class BaseConfig : public Config { CFG_FLOAT bm25_b; CFG_FLOAT bm25_avgdl; KNOHWERE_DECLARE_CONFIG(BaseConfig) { + KNOWHERE_CONFIG_DECLARE_FIELD(dim).allow_empty_without_default().description("vector dim").for_train(); KNOWHERE_CONFIG_DECLARE_FIELD(metric_type) .set_default("L2") .description("metric type") diff --git a/include/knowhere/index/index_static.h b/include/knowhere/index/index_static.h index 6a4816845..be0d0e92e 100644 --- a/include/knowhere/index/index_static.h +++ b/include/knowhere/index/index_static.h @@ -47,6 +47,7 @@ struct Resource { DEFINE_HAS_STATIC_FUNC(StaticCreateConfig) DEFINE_HAS_STATIC_FUNC(StaticEstimateLoadResource) DEFINE_HAS_STATIC_FUNC(StaticHasRawData) +DEFINE_HAS_STATIC_FUNC(StaticConfigCheck) template class IndexStaticFaced { @@ -61,6 +62,10 @@ class IndexStaticFaced { static std::unique_ptr CreateConfig(const knowhere::IndexType& indexType, const knowhere::IndexVersion& version); + static knowhere::Status + ConfigCheck(const knowhere::IndexType& indexType, const knowhere::IndexVersion& version, + const knowhere::Json& params, std::string& msg); + /** * @brief estimate the memory and disk resource usage before index loading by index params * @param indexType vector index type (HNSW, IVFFLAT, etc) @@ -103,6 +108,11 @@ class IndexStaticFaced { staticHasRawDataMap[indexType] = VecIndexNode::StaticHasRawData; } + if constexpr (has_static_StaticConfigCheck::InternalConfigCheck)>::value) { + staticConfigCheckMap[indexType] = VecIndexNode::StaticConfigCheck; + } + return Instance(); } @@ -117,12 +127,16 @@ class IndexStaticFaced { static bool InternalStaticHasRawData(const knowhere::BaseConfig& config, const IndexVersion& version); + static knowhere::Status + InternalConfigCheck(const knowhere::BaseConfig& config, const IndexVersion& version, std::string& msg); + static std::unique_ptr InternalStaticCreateConfig(); std::map> staticCreateConfigMap; std::map> staticHasRawDataMap; std::map> staticEstimateLoadResourceMap; + std::map> staticConfigCheckMap; }; } // namespace knowhere diff --git a/src/common/config.cc b/src/common/config.cc index f2ad0625a..81cec6461 100644 --- a/src/common/config.cc +++ b/src/common/config.cc @@ -20,6 +20,7 @@ #include "index/hnsw/hnsw_config.h" #include "index/ivf/ivf_config.h" #include "index/sparse/sparse_inverted_index_config.h" +#include "knowhere/index/index_factory.h" #include "knowhere/log.h" namespace knowhere { @@ -86,12 +87,26 @@ Config::FormatAndCheck(const Config& cfg, Json& json, std::string* const err_msg if (json.find(it.first) != json.end() && json[it.first].is_string()) { if (std::get_if>(&var)) { std::string::size_type sz; - auto value_str = json[it.first].get(); - CFG_INT::value_type v = std::stoi(value_str.c_str(), &sz); - if (sz < value_str.length()) { - KNOWHERE_THROW_MSG(std::string("wrong data type in json ") + value_str); + auto key_str = it.first; + auto value_str = json[key_str].get(); + try { + int64_t v = std::stoll(value_str, &sz); + if (sz < value_str.length()) { + KNOWHERE_THROW_MSG("wrong data type in json, key: '" + key_str + "', value: '" + value_str + + "'"); + } + if (v < std::numeric_limits::min() || + v > std::numeric_limits::max()) { + *err_msg = "integer value out of range, key: '" + key_str + "', value: '" + value_str + "'"; + return knowhere::Status::invalid_value_in_json; + } + json[key_str] = static_cast(v); + } catch (const std::out_of_range&) { + *err_msg = "integer value out of range, key: '" + key_str + "', value: '" + value_str + "'"; + return knowhere::Status::invalid_value_in_json; + } catch (const std::invalid_argument&) { + KNOWHERE_THROW_MSG("invalid integer value, key: '" + key_str + "', value: '" + value_str + "'"); } - json[it.first] = v; } if (std::get_if>(&var)) { CFG_FLOAT::value_type v = std::stof(json[it.first].get().c_str()); @@ -119,53 +134,3 @@ Config::FormatAndCheck(const Config& cfg, Json& json, std::string* const err_msg } } // namespace knowhere - -extern "C" __attribute__((visibility("default"))) int -CheckConfig(int index_type, char const* str, int n, int param_type); - -int -CheckConfig(int index_type, const char* str, int n, int param_type) { - if (!str || n <= 0) { - return int(knowhere::Status::invalid_args); - } - knowhere::Json json = knowhere::Json::parse(str, str + n); - std::unique_ptr cfg; - - switch (index_type) { - case 0: - cfg = std::make_unique(); - break; - case 1: - cfg = std::make_unique(); - break; - case 2: - cfg = std::make_unique(); - break; - case 3: - cfg = std::make_unique(); - break; - case 4: - cfg = std::make_unique(); - break; - case 5: - cfg = std::make_unique(); - break; - case 6: - cfg = std::make_unique(); - break; - case 7: - cfg = std::make_unique(); - break; - case 8: - cfg = std::make_unique(); - break; - default: - return int(knowhere::Status::invalid_args); - } - - auto res = knowhere::Config::FormatAndCheck(*cfg, json, nullptr); - if (res != knowhere::Status::success) { - return int(res); - } - return int(knowhere::Config::Load(*cfg, json, knowhere::PARAM_TYPE(param_type), nullptr)); -} diff --git a/src/index/gpu_raft/gpu_raft_brute_force_config.h b/src/index/gpu_raft/gpu_raft_brute_force_config.h index ccc36f7a8..79b2b595a 100644 --- a/src/index/gpu_raft/gpu_raft_brute_force_config.h +++ b/src/index/gpu_raft/gpu_raft_brute_force_config.h @@ -23,7 +23,20 @@ namespace knowhere { -struct GpuRaftBruteForceConfig : public BaseConfig {}; +struct GpuRaftBruteForceConfig : public BaseConfig { + Status + CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { + if (param_type == PARAM_TYPE::TRAIN) { + auto legal_metric_list = std::vector{"L2", "IP"}; + std::string metric = metric_type.value(); + if (std::find(legal_metric_list.begin(), legal_metric_list.end(), metric) == legal_metric_list.end()) { + *err_msg = "metric type " + metric + " not found or not supported, supported: [L2 IP]"; + return Status::invalid_metric_type; + } + } + return Status::success; + } +}; [[nodiscard]] inline auto to_raft_knowhere_config(GpuRaftBruteForceConfig const& cfg) { diff --git a/src/index/gpu_raft/gpu_raft_cagra_config.h b/src/index/gpu_raft/gpu_raft_cagra_config.h index b9a17c193..ad7de43ae 100644 --- a/src/index/gpu_raft/gpu_raft_cagra_config.h +++ b/src/index/gpu_raft/gpu_raft_cagra_config.h @@ -71,7 +71,7 @@ struct GpuRaftCagraConfig : public BaseConfig { KNOWHERE_CONFIG_DECLARE_FIELD(max_queries).description("maximum batch size").set_default(0).for_search(); KNOWHERE_CONFIG_DECLARE_FIELD(build_algo) .description("algorithm used to build knn graph") - .set_default("IVF_PQ") + .set_default("NN_DESCENT") .for_train(); KNOWHERE_CONFIG_DECLARE_FIELD(search_algo) .description("algorithm used for search") diff --git a/src/index/gpu_raft/gpu_raft_ivf_flat_config.h b/src/index/gpu_raft/gpu_raft_ivf_flat_config.h index 4d9eed752..80fa9e52e 100644 --- a/src/index/gpu_raft/gpu_raft_ivf_flat_config.h +++ b/src/index/gpu_raft/gpu_raft_ivf_flat_config.h @@ -57,6 +57,19 @@ struct GpuRaftIvfFlatConfig : public IvfFlatConfig { .set_default(false) .for_train(); } + + Status + CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { + if (param_type == PARAM_TYPE::TRAIN) { + auto legal_metric_list = std::vector{"L2", "IP"}; + std::string metric = metric_type.value(); + if (std::find(legal_metric_list.begin(), legal_metric_list.end(), metric) == legal_metric_list.end()) { + *err_msg = "metric type " + metric + " not found or not supported, supported: [L2 IP]"; + return Status::invalid_metric_type; + } + } + return Status::success; + } }; [[nodiscard]] inline auto diff --git a/src/index/gpu_raft/gpu_raft_ivf_pq_config.h b/src/index/gpu_raft/gpu_raft_ivf_pq_config.h index 402a528e8..346e3721e 100644 --- a/src/index/gpu_raft/gpu_raft_ivf_pq_config.h +++ b/src/index/gpu_raft/gpu_raft_ivf_pq_config.h @@ -92,6 +92,19 @@ struct GpuRaftIvfPqConfig : public IvfPqConfig { .set_default(1.0f) .for_search(); } + + Status + CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { + if (param_type == PARAM_TYPE::TRAIN) { + auto legal_metric_list = std::vector{"L2", "IP"}; + std::string metric = metric_type.value(); + if (std::find(legal_metric_list.begin(), legal_metric_list.end(), metric) == legal_metric_list.end()) { + *err_msg = "metric type " + metric + " not found or not supported, supported: [L2 IP]"; + return Status::invalid_metric_type; + } + } + return Status::success; + } }; [[nodiscard]] inline auto diff --git a/src/index/hnsw/hnsw.cc b/src/index/hnsw/hnsw.cc index 9cf77e097..05232e9ab 100644 --- a/src/index/hnsw/hnsw.cc +++ b/src/index/hnsw/hnsw.cc @@ -89,6 +89,33 @@ class HnswIndexNode : public IndexNode { return Status::success; } + static Status + StaticConfigCheck(const Config& cfg, PARAM_TYPE paramType, std::string& msg) { + auto hnsw_cfg = static_cast(cfg); + + if (paramType == PARAM_TYPE::TRAIN) { + if constexpr (KnowhereFloatTypeCheck::value) { + if (IsMetricType(hnsw_cfg.metric_type.value(), metric::L2) || + IsMetricType(hnsw_cfg.metric_type.value(), metric::IP) || + IsMetricType(hnsw_cfg.metric_type.value(), metric::COSINE)) { + } else { + msg = "metric type " + hnsw_cfg.metric_type.value() + + " not found or not supported, supported: [L2 IP COSINE]"; + return Status::invalid_metric_type; + } + } else { + if (IsMetricType(hnsw_cfg.metric_type.value(), metric::HAMMING) || + IsMetricType(hnsw_cfg.metric_type.value(), metric::JACCARD)) { + } else { + msg = "metric type " + hnsw_cfg.metric_type.value() + + " not found or not supported, supported: [HAMMING JACCARD]"; + return Status::invalid_metric_type; + } + } + } + return Status::success; + } + Status Add(const DataSetPtr dataset, std::shared_ptr cfg) override { if (!index_) { diff --git a/src/index/index_static.cc b/src/index/index_static.cc index 0804c85a3..4746f291c 100644 --- a/src/index/index_static.cc +++ b/src/index/index_static.cc @@ -44,6 +44,25 @@ IndexStaticFaced::CreateConfig(const IndexType& indexType, const Index return std::make_unique(); } +template +knowhere::Status +IndexStaticFaced::ConfigCheck(const IndexType& indexType, const IndexVersion& version, const Json& params, + std::string& msg) { + auto cfg = IndexStaticFaced::CreateConfig(indexType, version); + + const Status status = LoadStaticConfig(cfg.get(), params, knowhere::PARAM_TYPE::TRAIN, "ConfigCheck", &msg); + if (status != Status::success) { + LOG_KNOWHERE_ERROR_ << "Load Config failed, msg = " << msg; + return status; + } + + if (Instance().staticConfigCheckMap.find(indexType) != Instance().staticConfigCheckMap.end()) { + return Instance().staticConfigCheckMap[indexType](*cfg, version, msg); + } + + return knowhere::Status::success; +} + template expected IndexStaticFaced::EstimateLoadResource(const knowhere::IndexType& indexType, @@ -123,6 +142,13 @@ IndexStaticFaced::InternalStaticCreateConfig() { return std::unique_ptr(); } +template +knowhere::Status +IndexStaticFaced::InternalConfigCheck(const BaseConfig& config, const IndexVersion& version, + std::string& msg) { + return knowhere::Status::success; +} + template class IndexStaticFaced; template class IndexStaticFaced; template class IndexStaticFaced; diff --git a/src/index/ivf/ivf.cc b/src/index/ivf/ivf.cc index 8298e711e..894fe831a 100644 --- a/src/index/ivf/ivf.cc +++ b/src/index/ivf/ivf.cc @@ -79,6 +79,33 @@ class IvfIndexNode : public IndexNode { expected GetVectorByIds(const DataSetPtr dataset) const override; + static Status + StaticConfigCheck(const Config& cfg, PARAM_TYPE paramType, std::string& msg) { + auto ivf_cfg = static_cast(cfg); + + if (paramType == PARAM_TYPE::TRAIN) { + if constexpr (KnowhereFloatTypeCheck::value) { + if (IsMetricType(ivf_cfg.metric_type.value(), metric::L2) || + IsMetricType(ivf_cfg.metric_type.value(), metric::IP) || + IsMetricType(ivf_cfg.metric_type.value(), metric::COSINE)) { + } else { + msg = "metric type " + ivf_cfg.metric_type.value() + + " not found or not supported, supported: [L2 IP COSINE]"; + return Status::invalid_metric_type; + } + } else { + if (IsMetricType(ivf_cfg.metric_type.value(), metric::HAMMING) || + IsMetricType(ivf_cfg.metric_type.value(), metric::JACCARD)) { + } else { + msg = "metric type " + ivf_cfg.metric_type.value() + + " not found or not supported, supported: [HAMMING JACCARD]"; + return Status::invalid_metric_type; + } + } + } + return Status::success; + } + static bool CommonHasRawData() { if constexpr (std::is_same::value) { diff --git a/src/index/ivf/ivf_config.h b/src/index/ivf/ivf_config.h index 8a130f0a1..193477ba3 100644 --- a/src/index/ivf/ivf_config.h +++ b/src/index/ivf/ivf_config.h @@ -24,11 +24,7 @@ class IvfConfig : public BaseConfig { CFG_BOOL ensure_topk_full; // only take affect on temp index(IVF_FLAT_CC) now CFG_INT max_empty_result_buckets; KNOHWERE_DECLARE_CONFIG(IvfConfig) { - KNOWHERE_CONFIG_DECLARE_FIELD(nlist) - .set_default(128) - .description("number of inverted lists.") - .for_train() - .set_range(1, 65536); + KNOWHERE_CONFIG_DECLARE_FIELD(nlist).description("number of inverted lists.").for_train().set_range(1, 65536); KNOWHERE_CONFIG_DECLARE_FIELD(nprobe) .set_default(8) .description("number of probes at query time.") @@ -70,9 +66,28 @@ class IvfPqConfig : public IvfConfig { CFG_INT m; CFG_INT nbits; KNOHWERE_DECLARE_CONFIG(IvfPqConfig) { - KNOWHERE_CONFIG_DECLARE_FIELD(m).description("m").set_default(32).for_train().set_range(1, 65536); + KNOWHERE_CONFIG_DECLARE_FIELD(m).description("m").for_train().set_range(1, 65536); KNOWHERE_CONFIG_DECLARE_FIELD(nbits).description("nbits").set_default(8).for_train().set_range(1, 64); } + + Status + CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { + switch (param_type) { + case PARAM_TYPE::TRAIN: { + if (dim.has_value() && m.has_value()) { + int vec_dim = dim.value(); + int param_m = m.value(); + if (vec_dim % param_m != 0) { + *err_msg = + "dimension must be able to be divided by `m`, dimension: " + std::to_string(vec_dim) + + ", m: " + std::to_string(param_m); + return Status::invalid_args; + } + } + } + } + return Status::success; + } }; class ScannConfig : public IvfFlatConfig { @@ -95,6 +110,16 @@ class ScannConfig : public IvfFlatConfig { Status CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { switch (param_type) { + case PARAM_TYPE::TRAIN: { + // TODO: handle odd dim with scann + if (dim.has_value()) { + int vec_dim = dim.value(); + if (vec_dim % 2 != 0) { + *err_msg = "dimension must be able to be divided by 2, dimension:" + std::to_string(vec_dim); + return Status::invalid_args; + } + } + } case PARAM_TYPE::SEARCH: { if (!faiss::support_pq_fast_scan) { LOG_KNOWHERE_ERROR_ << "SCANN index is not supported on the current CPU model, avx2 support is " @@ -129,7 +154,20 @@ class ScannConfig : public IvfFlatConfig { class IvfSqConfig : public IvfConfig {}; -class IvfBinConfig : public IvfConfig {}; +class IvfBinConfig : public IvfConfig { + Status + CheckAndAdjust(PARAM_TYPE param_type, std::string* err_msg) override { + if (param_type == PARAM_TYPE::TRAIN) { + auto legal_metric_list = std::vector{"HAMMING", "JACCARD"}; + std::string metric = metric_type.value(); + if (std::find(legal_metric_list.begin(), legal_metric_list.end(), metric) == legal_metric_list.end()) { + *err_msg = "metric type " + metric + " not found or not supported, supported: [HAMMING JACCARD]"; + return Status::invalid_metric_type; + } + } + return Status::success; + } +}; class IvfSqCcConfig : public IvfFlatCcConfig { public: diff --git a/tests/ut/test_config.cc b/tests/ut/test_config.cc index b61126afc..318b8b66f 100644 --- a/tests/ut/test_config.cc +++ b/tests/ut/test_config.cc @@ -15,6 +15,8 @@ #include "index/hnsw/hnsw_config.h" #include "index/ivf/ivf_config.h" #include "knowhere/config.h" +#include "knowhere/index/index_factory.h" +#include "knowhere/version.h" #ifdef KNOWHERE_WITH_DISKANN #include "index/diskann/diskann_config.h" #endif @@ -22,6 +24,41 @@ #include "index/gpu_raft/gpu_raft_cagra_config.h" #endif +void +checkBuildConfig(knowhere::IndexType indexType, knowhere::Json& json) { + std::string msg; + if (knowhere::IndexFactory::Instance().FeatureCheck(indexType, knowhere::feature::BINARY)) { + CHECK(knowhere::IndexStaticFaced::ConfigCheck( + indexType, knowhere::Version::GetCurrentVersion().VersionNumber(), json, msg) == + knowhere::Status::success); + CHECK(msg.empty()); + } + if (knowhere::IndexFactory::Instance().FeatureCheck(indexType, knowhere::feature::FLOAT32)) { + CHECK(knowhere::IndexStaticFaced::ConfigCheck(indexType, + knowhere::Version::GetCurrentVersion().VersionNumber(), + json, msg) == knowhere::Status::success); + CHECK(msg.empty()); + } + if (knowhere::IndexFactory::Instance().FeatureCheck(indexType, knowhere::feature::BF16)) { + CHECK(knowhere::IndexStaticFaced::ConfigCheck( + indexType, knowhere::Version::GetCurrentVersion().VersionNumber(), json, msg) == + knowhere::Status::success); + CHECK(msg.empty()); + } + if (knowhere::IndexFactory::Instance().FeatureCheck(indexType, knowhere::feature::FP16)) { + CHECK(knowhere::IndexStaticFaced::ConfigCheck( + indexType, knowhere::Version::GetCurrentVersion().VersionNumber(), json, msg) == + knowhere::Status::success); + CHECK(msg.empty()); + } + if (knowhere::IndexFactory::Instance().FeatureCheck(indexType, knowhere::feature::SPARSE_FLOAT32)) { + CHECK(knowhere::IndexStaticFaced::ConfigCheck(indexType, + knowhere::Version::GetCurrentVersion().VersionNumber(), + json, msg) == knowhere::Status::success); + CHECK(msg.empty()); + } +} + TEST_CASE("Test config json parse", "[config]") { knowhere::Status s; std::string err_msg; @@ -96,9 +133,15 @@ TEST_CASE("Test config json parse", "[config]") { })"); knowhere::HnswConfig hnsw_config; s = knowhere::Config::FormatAndCheck(hnsw_config, large_build_json); + + checkBuildConfig(knowhere::IndexEnum::INDEX_HNSW, large_build_json); + CHECK(s == knowhere::Status::success); #ifdef KNOWHERE_WITH_DISKANN knowhere::DiskANNConfig diskann_config; + + checkBuildConfig(knowhere::IndexEnum::INDEX_DISKANN, large_build_json); + s = knowhere::Config::FormatAndCheck(diskann_config, large_build_json); CHECK(s == knowhere::Status::success); #endif @@ -137,6 +180,7 @@ TEST_CASE("Test config json parse", "[config]") { "k": 100 })"); + checkBuildConfig(knowhere::IndexEnum::INDEX_FAISS_IDMAP, json); knowhere::FlatConfig train_cfg; s = knowhere::Config::Load(train_cfg, json, knowhere::TRAIN); CHECK(s == knowhere::Status::success); @@ -160,6 +204,7 @@ TEST_CASE("Test config json parse", "[config]") { "trace_visit": true })"); knowhere::IvfFlatConfig train_cfg; + checkBuildConfig(knowhere::IndexEnum::INDEX_FAISS_IVFFLAT, json); s = knowhere::Config::Load(train_cfg, json, knowhere::TRAIN); CHECK(s == knowhere::Status::success); CHECK(train_cfg.metric_type.value() == "L2"); @@ -202,6 +247,7 @@ TEST_CASE("Test config json parse", "[config]") { knowhere::HnswConfig wrong_cfg; auto invalid_value_json = json; invalid_value_json["efConstruction"] = 100.10; + checkBuildConfig(knowhere::IndexEnum::INDEX_HNSW, json); s = knowhere::Config::Load(wrong_cfg, invalid_value_json, knowhere::TRAIN); CHECK(s == knowhere::Status::type_conflict_in_json); @@ -281,6 +327,7 @@ TEST_CASE("Test config json parse", "[config]") { })"); { knowhere::DiskANNConfig train_cfg; + checkBuildConfig(knowhere::IndexEnum::INDEX_DISKANN, json); s = knowhere::Config::Load(train_cfg, json, knowhere::TRAIN); CHECK(s == knowhere::Status::success); CHECK_EQ(128, train_cfg.search_list_size.value()); diff --git a/tests/ut/test_search.cc b/tests/ut/test_search.cc index 075c63d51..7463c5d82 100644 --- a/tests/ut/test_search.cc +++ b/tests/ut/test_search.cc @@ -510,12 +510,13 @@ TEST_CASE("Test Mem Index With Float Vector", "[float metrics]") { json[knowhere::meta::METRIC_TYPE] = knowhere::metric::L2; json[knowhere::meta::TOPK] = 10; json[knowhere::indexparam::M] = 15; + json[knowhere::indexparam::NLIST] = 128; json[knowhere::indexparam::NBITS] = 8; return json; }; auto train_ds = GenDataSet(nb, dim); auto res = idx.Build(train_ds, ivf_pq_gen()); - REQUIRE(res == knowhere::Status::faiss_inner_error); + REQUIRE(res == knowhere::Status::invalid_args); } SECTION("Test IVFPQ with invalid params") { @@ -529,6 +530,7 @@ TEST_CASE("Test Mem Index With Float Vector", "[float metrics]") { json[knowhere::meta::DIM] = dim; json[knowhere::meta::METRIC_TYPE] = knowhere::metric::L2; json[knowhere::meta::TOPK] = 10; + json[knowhere::indexparam::NLIST] = 128; json[knowhere::indexparam::CODE_SIZE] = 7; return json; }; @@ -760,7 +762,7 @@ TEST_CASE("Test Mem Index With Binary Vector", "[bool metrics]") { if (name == knowhere::IndexEnum::INDEX_FAISS_BIN_IDMAP) { REQUIRE(res == knowhere::Status::success); } else { - REQUIRE(res == knowhere::Status::faiss_inner_error); + REQUIRE(res == knowhere::Status::invalid_metric_type); return; } auto results = idx.Search(query_ds, json, nullptr);