diff --git a/sdk/examples/qps/main.cpp b/sdk/examples/qps/main.cpp index 88c362f724fdf9d81cf517dffde5c756f2a81267..af060fd5b94d7ae72e1866816bd232c5e7953fd5 100644 --- a/sdk/examples/qps/main.cpp +++ b/sdk/examples/qps/main.cpp @@ -27,14 +27,28 @@ main(int argc, char* argv[]) { static struct option long_options[] = {{"server", optional_argument, nullptr, 's'}, {"port", optional_argument, nullptr, 'p'}, {"help", no_argument, nullptr, 'h'}, + {"collection_name", no_argument, nullptr, 't'}, + {"index", optional_argument, nullptr, 'i'}, + {"index_file_size", optional_argument, nullptr, 'f'}, + {"nlist", optional_argument, nullptr, 'l'}, + {"metric", optional_argument, nullptr, 'm'}, + {"dimension", optional_argument, nullptr, 'd'}, + {"rowcount", optional_argument, nullptr, 'r'}, + {"concurrency", optional_argument, nullptr, 'c'}, + {"query_count", optional_argument, nullptr, 'q'}, + {"nq", optional_argument, nullptr, 'n'}, + {"topk", optional_argument, nullptr, 'k'}, + {"nprobe", optional_argument, nullptr, 'b'}, + {"print", optional_argument, nullptr, 'v'}, {nullptr, 0, nullptr, 0}}; int option_index = 0; std::string address = "127.0.0.1", port = "19530"; app_name = argv[0]; + TestParameters parameters; int value; - while ((value = getopt_long(argc, argv, "s:p:h", long_options, &option_index)) != -1) { + while ((value = getopt_long(argc, argv, "s:p:t:i:f:l:m:d:r:c:q:n:k:b:vh", long_options, &option_index)) != -1) { switch (value) { case 's': { char* address_ptr = strdup(optarg); @@ -48,6 +62,82 @@ main(int argc, char* argv[]) { free(port_ptr); break; } + case 't': { + char* ptr = strdup(optarg); + parameters.collection_name_ = ptr; + free(ptr); + break; + } + case 'i': { + char* ptr = strdup(optarg); + parameters.index_type_ = atol(ptr); + free(ptr); + break; + } + case 'f': { + char* ptr = strdup(optarg); + parameters.index_file_size_ = atol(ptr); + free(ptr); + break; + } + case 'l': { + char* ptr = strdup(optarg); + parameters.nlist_ = atol(ptr); + free(ptr); + break; + } + case 'm': { + char* ptr = strdup(optarg); + parameters.metric_type_ = atol(ptr); + free(ptr); + break; + } + case 'd': { + char* ptr = strdup(optarg); + parameters.dimensions_ = atol(ptr); + free(ptr); + break; + } + case 'r': { + char* ptr = strdup(optarg); + parameters.row_count_ = atol(ptr); + free(ptr); + break; + } + case 'c': { + char* ptr = strdup(optarg); + parameters.concurrency_ = atol(ptr); + free(ptr); + break; + } + case 'q': { + char* ptr = strdup(optarg); + parameters.query_count_ = atol(ptr); + free(ptr); + break; + } + case 'n': { + char* ptr = strdup(optarg); + parameters.nq_ = atol(ptr); + free(ptr); + break; + } + case 'k': { + char* ptr = strdup(optarg); + parameters.topk_ = atol(ptr); + free(ptr); + break; + } + case 'b': { + char* ptr = strdup(optarg); + parameters.nprobe_ = atol(ptr); + free(ptr); + break; + } + case 'v': { + parameters.print_result_ = true; + break; + } case 'h': default: print_help(app_name); @@ -56,9 +146,9 @@ main(int argc, char* argv[]) { } ClientTest test(address, port); - test.Test(); + test.Test(parameters); - printf("Client stop...\n"); + printf("Client exits ...\n"); return 0; } @@ -66,8 +156,25 @@ void print_help(const std::string& app_name) { printf("\n Usage: %s [OPTIONS]\n\n", app_name.c_str()); printf(" Options:\n"); - printf(" -s --server Server address, default 127.0.0.1\n"); - printf(" -p --port Server port, default 19530\n"); - printf(" -h --help Print help information\n"); + printf(" -s --server Server address, default:127.0.0.1\n"); + printf(" -p --port Server port, default:19530\n"); + printf(" -t --collection_name target collection name, specify this will ignore collection parameters, " + "default empty\n"); + printf(" -h --help Print help information\n"); + printf(" -i --index " + "Collection index type(1=IDMAP, 2=IVFLAT, 3=IVFSQ8, 5=IVFSQ8H), default:3\n"); + printf(" -f --index_file_size Collection index file size, default:1024\n"); + printf(" -l --nlist Collection index nlist, default:16384\n"); + printf(" -m --metric " + "Collection metric type(1=L2, 2=IP, 3=HAMMING, 4=JACCARD, 5=TANIMOTO, 6=SUBSTRUCTURE, 7=SUPERSTRUCTURE), " + "default:1\n"); + printf(" -d --dimension Collection dimension, default:128\n"); + printf(" -r --rowcount Collection total row count(unit:million), default:1\n"); + printf(" -c --concurrency Max client connections, default:20\n"); + printf(" -q --query_count Query total count, default:1000\n"); + printf(" -n --nq nq of each query, default:1\n"); + printf(" -k --topk topk of each query, default:10\n"); + printf(" -b --nprobe nprobe of each query, default:16\n"); + printf(" -v --print_result Print query result, default:false\n"); printf("\n"); } diff --git a/sdk/examples/qps/src/ClientTest.cpp b/sdk/examples/qps/src/ClientTest.cpp index de23be35da78cd2d6acc1ac2d49c527f09a9c3d3..7f6700a7b977386c9ffcf83088d423665d731c97 100644 --- a/sdk/examples/qps/src/ClientTest.cpp +++ b/sdk/examples/qps/src/ClientTest.cpp @@ -11,6 +11,7 @@ #include "examples/utils/TimeRecorder.h" #include "examples/utils/Utils.h" +#include "examples/utils/ThreadPool.h" #include "examples/qps/src/ClientTest.h" #include @@ -19,74 +20,45 @@ #include namespace { - -const char* COLLECTION_NAME = milvus_sdk::Utils::GenCollectionName().c_str(); - -constexpr int64_t COLLECTION_DIMENSION = 128; -constexpr int64_t COLLECTION_INDEX_FILE_SIZE = 512; -constexpr milvus::MetricType COLLECTION_METRIC_TYPE = milvus::MetricType::L2; constexpr int64_t BATCH_ENTITY_COUNT = 100000; -constexpr int64_t NQ = 5; -constexpr int64_t TOP_K = 10; -constexpr int64_t NPROBE = 16; constexpr int64_t ADD_ENTITY_LOOP = 10; -constexpr milvus::IndexType INDEX_TYPE = milvus::IndexType::IVFSQ8; -constexpr int32_t NLIST = 16384; - -// parallel query setting -constexpr int32_t QUERY_THREAD_COUNT = 20; -constexpr int32_t TOTAL_QUERY_COUNT = 1000; -bool PRINT_RESULT = false; bool -InsertEntities(std::shared_ptr& conn) { - for (int i = 0; i < ADD_ENTITY_LOOP; i++) { - std::vector entity_array; - std::vector record_ids; - int64_t begin_index = i * BATCH_ENTITY_COUNT; - { // generate vectors - milvus_sdk::TimeRecorder rc("Build entities No." + std::to_string(i)); - milvus_sdk::Utils::BuildEntities(begin_index, - begin_index + BATCH_ENTITY_COUNT, - entity_array, - record_ids, - COLLECTION_DIMENSION); - } - - std::string title = "Insert " + std::to_string(entity_array.size()) + " entities No." + std::to_string(i); - milvus_sdk::TimeRecorder rc(title); - milvus::Status stat = conn->Insert(COLLECTION_NAME, "", entity_array, record_ids); - std::cout << "InsertEntities function call status: " << stat.message() << std::endl; - std::cout << "Returned id array count: " << record_ids.size() << std::endl; - - stat = conn->FlushCollection(COLLECTION_NAME); +IsSupportedIndex(int64_t index) { + if (index != (int64_t)milvus::IndexType::FLAT + && index != (int64_t)milvus::IndexType::IVFFLAT + && index != (int64_t)milvus::IndexType::IVFSQ8 + && index != (int64_t)milvus::IndexType::IVFSQ8H) { + std::cout << "Unsupported index type: " << index << std::endl; + return false; } return true; } -void -PrintSearchResult(int64_t batch_num, const milvus::TopKQueryResult& result) { - if (!PRINT_RESULT) { - return; +class ConnectionWrapper { + public: + explicit ConnectionWrapper(std::shared_ptr& connection) + : connection_(connection) { } - std::cout << "No." << batch_num << " query result:" << std::endl; - for (size_t i = 0; i < result.size(); i++) { - std::cout << "\tNQ_" << i; - const milvus::QueryResult& one_result = result[i]; - size_t topk = one_result.ids.size(); - for (size_t j = 0; j < topk; j++) { - std::cout << "\t[" << one_result.ids[j] << ", " << one_result.distances[j] << "]"; + ~ConnectionWrapper() { + if (connection_) { + milvus::Connection::Destroy(connection_); } - std::cout << std::endl; } -} + + std::shared_ptr& Connection() { + return connection_; + } + private: + std::shared_ptr connection_; +}; } // namespace ClientTest::ClientTest(const std::string& address, const std::string& port) - : server_ip_(address), server_port_(port), query_thread_pool_(QUERY_THREAD_COUNT, QUERY_THREAD_COUNT * 2) { + : server_ip_(address), server_port_(port) { } ClientTest::~ClientTest() { @@ -105,103 +77,284 @@ ClientTest::Connect() { return conn; } +bool +ClientTest::CheckParameters(const TestParameters& parameters) { + if (!IsSupportedIndex(parameters.index_type_)) { + return false; + } + + if (parameters.metric_type_ <= 0 || parameters.metric_type_ > (int64_t)milvus::MetricType::SUPERSTRUCTURE) { + std::cout << "Invalid metric type: " << parameters.metric_type_ << std::endl; + return false; + } + + if (parameters.row_count_ <= 0) { + std::cout << "Invalid row count: " << parameters.row_count_ << std::endl; + return false; + } + + if (parameters.concurrency_ <= 0) { + std::cout << "Invalid concurrency: " << parameters.concurrency_ << std::endl; + return false; + } + + if (parameters.query_count_ <= 0) { + std::cout << "Invalid query count: " << parameters.query_count_ << std::endl; + return false; + } + + if (parameters.nq_ <= 0) { + std::cout << "Invalid query nq: " << parameters.nq_ << std::endl; + return false; + } + + if (parameters.topk_ <= 0 || parameters.topk_ > 2048) { + std::cout << "Invalid query topk: " << parameters.topk_ << std::endl; + return false; + } + + if (parameters.nprobe_ <= 0) { + std::cout << "Invalid query nprobe: " << parameters.nprobe_ << std::endl; + return false; + } + + return true; +} + bool ClientTest::BuildCollection() { std::shared_ptr conn = Connect(); + ConnectionWrapper wrapper(conn); if (conn == nullptr) { return false; } - milvus::CollectionParam - collection_param = {COLLECTION_NAME, COLLECTION_DIMENSION, COLLECTION_INDEX_FILE_SIZE, COLLECTION_METRIC_TYPE}; + std::string collection_name = parameters_.collection_name_; + if (collection_name.empty()) { + collection_name = milvus_sdk::Utils::GenCollectionName(); + parameters_.collection_name_ = collection_name; + } + + milvus::CollectionParam collection_param = { + collection_name, + parameters_.dimensions_, + parameters_.index_file_size_, + (milvus::MetricType)parameters_.metric_type_ + }; + + std::cout << "Create collection " << collection_param.collection_name << std::endl; auto stat = conn->CreateCollection(collection_param); - std::cout << "CreateCollection function call status: " << stat.message() << std::endl; if (!stat.ok()) { + std::cout << "CreateCollection function call status: " << stat.message() << std::endl; return false; } InsertEntities(conn); - milvus::Connection::Destroy(conn); + CreateIndex(conn); + return true; +} + +bool +ClientTest::InsertEntities(std::shared_ptr& conn) { + int64_t batch_count = parameters_.row_count_ * ADD_ENTITY_LOOP; + for (int i = 0; i < batch_count; i++) { + std::vector entity_array; + std::vector record_ids; + int64_t begin_index = i * BATCH_ENTITY_COUNT; + { // generate vectors +// milvus_sdk::TimeRecorder rc("Build entities No." + std::to_string(i)); + milvus_sdk::Utils::BuildEntities(begin_index, + begin_index + BATCH_ENTITY_COUNT, + entity_array, + record_ids, + parameters_.dimensions_); + } + + std::string title = "Insert " + std::to_string(entity_array.size()) + " entities No." + std::to_string(i); + milvus_sdk::TimeRecorder rc(title); + milvus::Status stat = conn->Insert(parameters_.collection_name_, "", entity_array, record_ids); + if (!stat.ok()) { + std::cout << "CreateIndex function call status: " << stat.message() << std::endl; + } +// std::cout << "InsertEntities function call status: " << stat.message() << std::endl; +// std::cout << "Returned id array count: " << record_ids.size() << std::endl; + + stat = conn->FlushCollection(parameters_.collection_name_); + } + return true; } void -ClientTest::CreateIndex() { +ClientTest::CreateIndex(std::shared_ptr& conn) { + std::string title = "Create index " + milvus_sdk::Utils::IndexTypeName((milvus::IndexType)parameters_.index_type_); + milvus_sdk::TimeRecorder rc(title); + JSON json_params = {{"nlist", parameters_.nlist_}}; + milvus::IndexParam + index = {parameters_.collection_name_, (milvus::IndexType)parameters_.index_type_, json_params.dump()}; + milvus_sdk::Utils::PrintIndexParam(index); + milvus::Status stat = conn->CreateIndex(index); + if (!stat.ok()) { + std::cout << "CreateIndex function call status: " << stat.message() << std::endl; + } +} + +bool +ClientTest::PreloadCollection() { std::shared_ptr conn = Connect(); + ConnectionWrapper wrapper(conn); if (conn == nullptr) { - return; + return false; } - std::cout << "Wait create index ..." << std::endl; - JSON json_params = {{"nlist", NLIST}}; - milvus::IndexParam index = {COLLECTION_NAME, INDEX_TYPE, json_params.dump()}; - milvus_sdk::Utils::PrintIndexParam(index); - milvus::Status stat = conn->CreateIndex(index); - std::cout << "CreateIndex function call status: " << stat.message() << std::endl; + if (!conn->HasCollection(parameters_.collection_name_)) { + std::cout << "Collection not found: " << parameters_.collection_name_ << std::endl; + return false; + } + + std::string title = "Preload table " + parameters_.collection_name_; + milvus_sdk::TimeRecorder rc(title); + milvus::Status stat = conn->PreloadCollection(parameters_.collection_name_); + if (!stat.ok()) { + std::string msg = "PreloadCollection function call status: " + stat.message(); + std::cout << msg << std::endl; + return false; + } + + return true; +} + +bool +ClientTest::GetCollectionInfo() { + std::shared_ptr conn = Connect(); + ConnectionWrapper wrapper(conn); + if (conn == nullptr) { + return false; + } + + milvus::CollectionParam collection_param; + milvus::Status stat = conn->DescribeCollection(parameters_.collection_name_, collection_param); + + milvus::IndexParam index_param; + stat = conn->DescribeIndex(parameters_.collection_name_, index_param); + + int64_t row_count = 0; + stat = conn->CountCollection(parameters_.collection_name_, row_count); + + parameters_.index_type_ = (int64_t)index_param.index_type; + if (!IsSupportedIndex(parameters_.index_type_)) { + return false; + } + parameters_.row_count_ = row_count; + parameters_.dimensions_ = collection_param.dimension; + parameters_.metric_type_ = (int64_t)collection_param.metric_type; + parameters_.index_file_size_ = collection_param.index_file_size; + + return true; } void ClientTest::DropCollection() { std::shared_ptr conn = Connect(); + ConnectionWrapper wrapper(conn); if (conn == nullptr) { return; } - milvus::Status stat = conn->DropCollection(COLLECTION_NAME); - std::cout << "DropCollection function call status: " << stat.message() << std::endl; + milvus::Status stat = conn->DropCollection(parameters_.collection_name_); + if (!stat.ok()) { + std::string msg = "DropCollection function call status: " + stat.message(); + std::cout << msg << std::endl; + } } void ClientTest::BuildSearchEntities(std::vector& entity_array) { entity_array.clear(); - for (int64_t i = 0; i < TOTAL_QUERY_COUNT; i++) { + for (int64_t i = 0; i < parameters_.query_count_; i++) { std::vector entities; std::vector record_ids; int64_t batch_index = i % ADD_ENTITY_LOOP; int64_t offset = batch_index * BATCH_ENTITY_COUNT; - milvus_sdk::Utils::BuildEntities(offset, offset + NQ, entities, record_ids, COLLECTION_DIMENSION); + milvus_sdk::Utils::BuildEntities(offset, + offset + parameters_.nq_, + entities, + record_ids, + parameters_.dimensions_); entity_array.emplace_back(entities); } - -// std::cout << "Build search entities finish" << std::endl; } void ClientTest::Search() { + if (!PreloadCollection()) { + return; + } + + if (!GetCollectionInfo()) { + return; + } + std::vector search_entities; BuildSearchEntities(search_entities); - query_thread_results_.clear(); + std::list> query_thread_results; + milvus_sdk::ThreadPool query_thread_pool(parameters_.concurrency_, parameters_.concurrency_ * 2); auto start = std::chrono::system_clock::now(); - // multi-threads query - for (int32_t i = 0; i < TOTAL_QUERY_COUNT; i++) { - query_thread_results_.push_back(query_thread_pool_.enqueue(&ClientTest::SearchWorker, - this, - search_entities[i])); + { + std::string title = "Searching " + parameters_.collection_name_; + milvus_sdk::TimeRecorder rc(title); + + // multi-threads query + for (int32_t i = 0; i < parameters_.query_count_; i++) { + query_thread_results.push_back(query_thread_pool.enqueue(&ClientTest::SearchWorker, + this, + search_entities[i])); + } + + // wait all query return + for (auto& iter : query_thread_results) { + iter.wait(); + } } - // wait all query return - for (auto& iter : query_thread_results_) { - iter.wait(); + // print result + int64_t index = 0; + for (auto& iter : query_thread_results) { + milvus::TopKQueryResult result = iter.get(); + CheckSearchResult(index, result); + PrintSearchResult(index, result); + index++; } + // calculate qps std::chrono::system_clock::time_point end = std::chrono::system_clock::now(); int64_t span = (std::chrono::duration_cast(end - start)).count(); double sec = (double)span / 1000.0; - std::cout << "data information: dimension = " << COLLECTION_DIMENSION << " row_count = " - << BATCH_ENTITY_COUNT * ADD_ENTITY_LOOP << std::endl; - std::cout << "search parameters: nq = " << NQ << " topk = " << TOP_K << " nprobe = " << NPROBE << std::endl; - std::cout << "search threads = " << QUERY_THREAD_COUNT << " total_query_count = " << TOTAL_QUERY_COUNT << std::endl; - std::cout << "search " << TOTAL_QUERY_COUNT << " times totally cost: " << span << " ms" << std::endl; - std::cout << "search qps = " << TOTAL_QUERY_COUNT / sec << std::endl; - - // print result - int64_t index = 0; - for (auto& iter : query_thread_results_) { - PrintSearchResult(index++, iter.get()); - } + double tps_s = parameters_.query_count_ / sec; + int64_t tps = (int64_t)tps_s; + int64_t qps = tps * parameters_.nq_; + std::cout << "TPS = " << tps << " \tQPS = " << qps << std::endl; + + // print search detail statistics + JSON search_stats = JSON(); + search_stats["table_name"] = parameters_.collection_name_; + search_stats["index"] = milvus_sdk::Utils::IndexTypeName((milvus::IndexType)parameters_.index_type_); + search_stats["index_file_size"] = parameters_.index_file_size_; + search_stats["nlist"] = parameters_.nlist_; + search_stats["metric"] = milvus_sdk::Utils::MetricTypeName((milvus::MetricType)parameters_.metric_type_); + search_stats["dimension"] = parameters_.dimensions_; + search_stats["row_count"] = parameters_.row_count_; + search_stats["concurrency"] = parameters_.concurrency_; + search_stats["query_count"] = parameters_.query_count_; + search_stats["nq"] = parameters_.nq_; + search_stats["topk"] = parameters_.topk_; + search_stats["nprobe"] = parameters_.nprobe_; + search_stats["qps"] = qps; + search_stats["tps"] = tps; + std::cout << search_stats.dump() << std::endl; } milvus::TopKQueryResult @@ -219,12 +372,12 @@ ClientTest::SearchWorker(EntityList& entities) { return res; } - JSON json_params = {{"nprobe", NPROBE}}; + JSON json_params = {{"nprobe", parameters_.nprobe_}}; std::vector partition_tags; - stat = conn->Search(COLLECTION_NAME, + stat = conn->Search(parameters_.collection_name_, partition_tags, entities, - TOP_K, + parameters_.topk_, json_params.dump(), res); if (!stat.ok()) { @@ -239,20 +392,52 @@ ClientTest::SearchWorker(EntityList& entities) { } void -ClientTest::Test() { - if (!BuildCollection()) { +ClientTest::PrintSearchResult(int64_t batch_num, const milvus::TopKQueryResult& result) { + if (!parameters_.print_result_) { return; } - // search without index - std::cout << "Search without index" << std::endl; - Search(); + std::cout << "No." << batch_num << " query result:" << std::endl; + for (size_t i = 0; i < result.size(); i++) { + std::cout << "\tNQ_" << i; + const milvus::QueryResult& one_result = result[i]; + size_t topk = one_result.ids.size(); + for (size_t j = 0; j < topk; j++) { + std::cout << "\t[" << one_result.ids[j] << ", " << one_result.distances[j] << "]"; + } + std::cout << std::endl; + } +} + +void +ClientTest::CheckSearchResult(int64_t batch_num, const milvus::TopKQueryResult& result) { + if (result.empty()) { + std::cout << "ERROR! No." << batch_num << " query return empty result" << std::endl; + return; + } + for (auto& res : result) { + if (res.ids.empty()) { + std::cout << "ERROR! No." << batch_num << " query return empty id" << std::endl; + return; + } + } +} - CreateIndex(); +void +ClientTest::Test(const TestParameters& parameters) { + if (!CheckParameters(parameters)) { + return; + } - // search with index - std::cout << "Search with index" << std::endl; - Search(); + parameters_ = parameters; + if (parameters_.collection_name_.empty()) { + if (!BuildCollection()) { + return; + } - DropCollection(); + Search(); + DropCollection(); + } else { + Search(); + } } diff --git a/sdk/examples/qps/src/ClientTest.h b/sdk/examples/qps/src/ClientTest.h index 311f22bb8bde5e7cf1d9c26ea009658bacf78987..a29e0c326472637fe07bb86ef6c4fae1e6d8b93b 100644 --- a/sdk/examples/qps/src/ClientTest.h +++ b/sdk/examples/qps/src/ClientTest.h @@ -12,7 +12,6 @@ #pragma once #include "include/MilvusApi.h" -#include "examples/utils/ThreadPool.h" #include #include @@ -20,23 +19,56 @@ #include #include +struct TestParameters { + // specify this will ignore index_type/index_file_size/nlist/metric_type/dimension/dow_count + std::string collection_name_; + + // collection parameters, only works when collection_name_ is empty + int64_t index_type_ = (int64_t)milvus::IndexType::IVFSQ8; // sq8 + int64_t index_file_size_ = 1024; // 1024 MB + int64_t nlist_ = 16384; + int64_t metric_type_ = (int64_t)milvus::MetricType::L2; // L2 + int64_t dimensions_ = 128; + int64_t row_count_ = 1; // 1 million + + // query parameters + int64_t concurrency_ = 20; // 20 connections + int64_t query_count_ = 1000; + int64_t nq_ = 1; + int64_t topk_ = 10; + int64_t nprobe_ = 16; + bool print_result_ = false; +}; + class ClientTest { public: ClientTest(const std::string&, const std::string&); ~ClientTest(); void - Test(); + Test(const TestParameters& parameters); private: std::shared_ptr Connect(); + bool + CheckParameters(const TestParameters& parameters); + bool BuildCollection(); + bool + InsertEntities(std::shared_ptr& conn); + void - CreateIndex(); + CreateIndex(std::shared_ptr& conn); + + bool + PreloadCollection(); + + bool + GetCollectionInfo(); void DropCollection(); @@ -51,10 +83,15 @@ class ClientTest { milvus::TopKQueryResult SearchWorker(EntityList& entities); + void + PrintSearchResult(int64_t batch_num, const milvus::TopKQueryResult& result); + + void + CheckSearchResult(int64_t batch_num, const milvus::TopKQueryResult& result); + private: std::string server_ip_; std::string server_port_; - milvus_sdk::ThreadPool query_thread_pool_; - std::list> query_thread_results_; + TestParameters parameters_; };