550 lines
22 KiB
C++
550 lines
22 KiB
C++
// Copyright 2025-present the zvec project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <gtest/gtest.h>
|
|
#include "db/index/common/proto_converter.h"
|
|
#include "db/index/common/type_helper.h"
|
|
|
|
using namespace zvec;
|
|
|
|
TEST(ConverterTest, InvertIndexParamsConversion) {
|
|
// Test conversion from protobuf to C++ InvertIndexParams
|
|
proto::InvertIndexParams invert_pb;
|
|
invert_pb.set_enable_range_optimization(true);
|
|
|
|
auto invert_params = ProtoConverter::FromPb(invert_pb);
|
|
ASSERT_NE(invert_params, nullptr);
|
|
EXPECT_TRUE(invert_params->enable_range_optimization());
|
|
EXPECT_EQ(invert_params->type(), IndexType::INVERT);
|
|
|
|
// Test with false value
|
|
proto::InvertIndexParams invert_pb2;
|
|
invert_pb2.set_enable_range_optimization(false);
|
|
|
|
auto invert_params2 = ProtoConverter::FromPb(invert_pb2);
|
|
ASSERT_NE(invert_params2, nullptr);
|
|
EXPECT_FALSE(invert_params2->enable_range_optimization());
|
|
|
|
// Test conversion from C++ to protobuf
|
|
InvertIndexParams original_params(true);
|
|
auto pb_result = ProtoConverter::ToPb(&original_params);
|
|
EXPECT_TRUE(pb_result.enable_range_optimization());
|
|
}
|
|
|
|
TEST(ConverterTest, HnswIndexParamsConversion) {
|
|
// Test conversion from protobuf to C++ HnswIndexParams
|
|
proto::HnswIndexParams hnsw_pb;
|
|
auto *base_params = hnsw_pb.mutable_base();
|
|
base_params->set_metric_type(proto::MT_L2);
|
|
base_params->set_quantize_type(proto::QT_FP16);
|
|
hnsw_pb.set_m(16);
|
|
hnsw_pb.set_ef_construction(100);
|
|
|
|
auto hnsw_params = ProtoConverter::FromPb(hnsw_pb);
|
|
ASSERT_NE(hnsw_params, nullptr);
|
|
EXPECT_EQ(hnsw_params->metric_type(), MetricType::L2);
|
|
EXPECT_EQ(hnsw_params->m(), 16);
|
|
EXPECT_EQ(hnsw_params->ef_construction(), 100);
|
|
EXPECT_EQ(hnsw_params->quantize_type(), QuantizeType::FP16);
|
|
EXPECT_EQ(hnsw_params->type(), IndexType::HNSW);
|
|
|
|
// Test conversion from C++ to protobuf
|
|
HnswIndexParams original_params(MetricType::IP, 32, 200, QuantizeType::INT8);
|
|
auto pb_result = ProtoConverter::ToPb(&original_params);
|
|
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_IP);
|
|
EXPECT_EQ(pb_result.m(), 32);
|
|
EXPECT_EQ(pb_result.ef_construction(), 200);
|
|
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_INT8);
|
|
}
|
|
|
|
TEST(ConverterTest, FlatIndexParamsConversion) {
|
|
// Test conversion from protobuf to C++ FlatIndexParams
|
|
proto::FlatIndexParams flat_pb;
|
|
auto *base_params = flat_pb.mutable_base();
|
|
base_params->set_metric_type(proto::MT_COSINE);
|
|
base_params->set_quantize_type(proto::QT_INT4);
|
|
|
|
auto flat_params = ProtoConverter::FromPb(flat_pb);
|
|
ASSERT_NE(flat_params, nullptr);
|
|
EXPECT_EQ(flat_params->metric_type(), MetricType::COSINE);
|
|
EXPECT_EQ(flat_params->quantize_type(), QuantizeType::INT4);
|
|
EXPECT_EQ(flat_params->type(), IndexType::FLAT);
|
|
|
|
// Test conversion from C++ to protobuf
|
|
FlatIndexParams original_params(MetricType::L2, QuantizeType::FP16);
|
|
auto pb_result = ProtoConverter::ToPb(&original_params);
|
|
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_L2);
|
|
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_FP16);
|
|
}
|
|
|
|
TEST(ConverterTest, IVFIndexParamsConversion) {
|
|
// Test conversion from protobuf to C++ IVFIndexParams
|
|
proto::IVFIndexParams ivf_pb;
|
|
auto *base_params = ivf_pb.mutable_base();
|
|
base_params->set_metric_type(proto::MT_IP);
|
|
base_params->set_quantize_type(proto::QT_INT8);
|
|
ivf_pb.set_n_list(128);
|
|
|
|
auto ivf_params = ProtoConverter::FromPb(ivf_pb);
|
|
ASSERT_NE(ivf_params, nullptr);
|
|
EXPECT_EQ(ivf_params->metric_type(), MetricType::IP);
|
|
EXPECT_EQ(ivf_params->n_list(), 128);
|
|
EXPECT_EQ(ivf_params->quantize_type(), QuantizeType::INT8);
|
|
EXPECT_EQ(ivf_params->type(), IndexType::IVF);
|
|
|
|
// Test conversion from C++ to protobuf
|
|
IVFIndexParams original_params(MetricType::COSINE, 256, 10, false,
|
|
QuantizeType::INT4);
|
|
auto pb_result = ProtoConverter::ToPb(&original_params);
|
|
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_COSINE);
|
|
EXPECT_EQ(pb_result.n_list(), 256);
|
|
EXPECT_EQ(pb_result.n_iters(), 10);
|
|
EXPECT_FALSE(pb_result.use_soar());
|
|
EXPECT_EQ(pb_result.base().quantize_type(), proto::QT_INT4);
|
|
}
|
|
|
|
TEST(ConverterTest, IndexParamsConversion) {
|
|
// Test conversion from protobuf to C++ IndexParams for HNSW
|
|
proto::IndexParams index_pb;
|
|
auto *hnsw_pb = index_pb.mutable_hnsw();
|
|
auto *base_params = hnsw_pb->mutable_base();
|
|
base_params->set_metric_type(proto::MT_L2);
|
|
base_params->set_quantize_type(proto::QT_FP16);
|
|
hnsw_pb->set_m(16);
|
|
hnsw_pb->set_ef_construction(100);
|
|
|
|
auto index_params = ProtoConverter::FromPb(index_pb);
|
|
ASSERT_NE(index_params, nullptr);
|
|
EXPECT_EQ(index_params->type(), IndexType::HNSW);
|
|
auto hnsw_cast = std::dynamic_pointer_cast<HnswIndexParams>(index_params);
|
|
ASSERT_NE(hnsw_cast, nullptr);
|
|
EXPECT_EQ(hnsw_cast->metric_type(), MetricType::L2);
|
|
EXPECT_EQ(hnsw_cast->m(), 16);
|
|
EXPECT_EQ(hnsw_cast->ef_construction(), 100);
|
|
EXPECT_EQ(hnsw_cast->quantize_type(), QuantizeType::FP16);
|
|
|
|
// Test conversion from C++ HnswIndexParams to protobuf IndexParams
|
|
HnswIndexParams hnsw_original(MetricType::IP, 32, 200);
|
|
auto pb_result = ProtoConverter::ToPb(&hnsw_original);
|
|
EXPECT_EQ(pb_result.base().metric_type(), proto::MT_IP);
|
|
EXPECT_EQ(pb_result.m(), 32);
|
|
EXPECT_EQ(pb_result.ef_construction(), 200);
|
|
|
|
// Test conversion from protobuf to C++ IndexParams for FLAT
|
|
proto::IndexParams index_pb2;
|
|
auto *flat_pb = index_pb2.mutable_flat();
|
|
auto *base_params2 = flat_pb->mutable_base();
|
|
base_params2->set_metric_type(proto::MT_COSINE);
|
|
base_params2->set_quantize_type(proto::QT_INT8);
|
|
|
|
auto index_params2 = ProtoConverter::FromPb(index_pb2);
|
|
ASSERT_NE(index_params2, nullptr);
|
|
EXPECT_EQ(index_params2->type(), IndexType::FLAT);
|
|
auto flat_cast = std::dynamic_pointer_cast<FlatIndexParams>(index_params2);
|
|
ASSERT_NE(flat_cast, nullptr);
|
|
EXPECT_EQ(flat_cast->metric_type(), MetricType::COSINE);
|
|
EXPECT_EQ(flat_cast->quantize_type(), QuantizeType::INT8);
|
|
|
|
// Test conversion from C++ FlatIndexParams to protobuf IndexParams
|
|
FlatIndexParams flat_original(MetricType::L2);
|
|
auto pb_result2 = ProtoConverter::ToPb(&flat_original);
|
|
EXPECT_EQ(pb_result2.base().metric_type(), proto::MT_L2);
|
|
|
|
// Test conversion from protobuf to C++ IndexParams for IVF
|
|
proto::IndexParams index_pb3;
|
|
auto *ivf_pb = index_pb3.mutable_ivf();
|
|
auto *base_params3 = ivf_pb->mutable_base();
|
|
base_params3->set_metric_type(proto::MT_IP);
|
|
base_params3->set_quantize_type(proto::QT_INT4);
|
|
ivf_pb->set_n_list(128);
|
|
|
|
auto index_params3 = ProtoConverter::FromPb(index_pb3);
|
|
ASSERT_NE(index_params3, nullptr);
|
|
EXPECT_EQ(index_params3->type(), IndexType::IVF);
|
|
auto ivf_cast = std::dynamic_pointer_cast<IVFIndexParams>(index_params3);
|
|
ASSERT_NE(ivf_cast, nullptr);
|
|
EXPECT_EQ(ivf_cast->metric_type(), MetricType::IP);
|
|
EXPECT_EQ(ivf_cast->n_list(), 128);
|
|
EXPECT_EQ(ivf_cast->quantize_type(), QuantizeType::INT4);
|
|
|
|
// Test conversion from C++ IVFIndexParams to protobuf IndexParams
|
|
IVFIndexParams ivf_original(MetricType::COSINE, 256);
|
|
auto pb_result3 = ProtoConverter::ToPb(&ivf_original);
|
|
EXPECT_EQ(pb_result3.base().metric_type(), proto::MT_COSINE);
|
|
EXPECT_EQ(pb_result3.n_list(), 256);
|
|
|
|
// Test conversion from protobuf to C++ IndexParams for INVERT
|
|
proto::IndexParams index_pb4;
|
|
auto *invert_pb = index_pb4.mutable_invert();
|
|
invert_pb->set_enable_range_optimization(true);
|
|
|
|
auto index_params4 = ProtoConverter::FromPb(index_pb4);
|
|
ASSERT_NE(index_params4, nullptr);
|
|
EXPECT_EQ(index_params4->type(), IndexType::INVERT);
|
|
auto invert_cast =
|
|
std::dynamic_pointer_cast<InvertIndexParams>(index_params4);
|
|
ASSERT_NE(invert_cast, nullptr);
|
|
EXPECT_TRUE(invert_cast->enable_range_optimization());
|
|
|
|
// Test conversion from C++ InvertIndexParams to protobuf IndexParams
|
|
InvertIndexParams invert_original(false);
|
|
auto pb_result4 = ProtoConverter::ToPb(&invert_original);
|
|
EXPECT_FALSE(pb_result4.enable_range_optimization());
|
|
}
|
|
|
|
TEST(ConverterTest, FieldSchemaConversion) {
|
|
// Test conversion from protobuf to C++ FieldSchema
|
|
proto::FieldSchema field_pb;
|
|
field_pb.set_name("test_field");
|
|
field_pb.set_data_type(proto::DT_VECTOR_FP32);
|
|
field_pb.set_dimension(128);
|
|
field_pb.set_nullable(true);
|
|
|
|
// Add index params
|
|
auto *index_params_pb = field_pb.mutable_index_params();
|
|
auto *hnsw_pb = index_params_pb->mutable_hnsw();
|
|
auto *base_params = hnsw_pb->mutable_base();
|
|
base_params->set_metric_type(proto::MT_L2);
|
|
base_params->set_quantize_type(proto::QT_FP16);
|
|
hnsw_pb->set_m(16);
|
|
hnsw_pb->set_ef_construction(100);
|
|
|
|
auto field_schema = ProtoConverter::FromPb(field_pb);
|
|
ASSERT_NE(field_schema, nullptr);
|
|
EXPECT_EQ(field_schema->name(), "test_field");
|
|
EXPECT_EQ(field_schema->data_type(), DataType::VECTOR_FP32);
|
|
EXPECT_TRUE(field_schema->nullable());
|
|
EXPECT_EQ(field_schema->dimension(), 128u);
|
|
ASSERT_NE(field_schema->index_params(), nullptr);
|
|
EXPECT_EQ(field_schema->index_params()->type(), IndexType::HNSW);
|
|
|
|
// Test conversion from C++ to protobuf
|
|
FieldSchema original_field("another_field", DataType::ARRAY_INT32, 64, false,
|
|
nullptr);
|
|
auto pb_result = ProtoConverter::ToPb(original_field);
|
|
EXPECT_EQ(pb_result.name(), "another_field");
|
|
EXPECT_EQ(pb_result.data_type(), proto::DT_ARRAY_INT32);
|
|
EXPECT_FALSE(pb_result.nullable());
|
|
EXPECT_EQ(pb_result.dimension(), 64u);
|
|
}
|
|
|
|
TEST(ConverterTest, CollectionSchemaConversion) {
|
|
// Test conversion from protobuf to C++ CollectionSchema
|
|
proto::CollectionSchema schema_pb;
|
|
schema_pb.set_name("test_collection");
|
|
schema_pb.set_max_doc_count_per_segment(1000000);
|
|
|
|
auto *field1_pb = schema_pb.add_fields();
|
|
field1_pb->set_name("field1");
|
|
field1_pb->set_data_type(proto::DT_STRING);
|
|
|
|
auto *field2_pb = schema_pb.add_fields();
|
|
field2_pb->set_name("field2");
|
|
field2_pb->set_data_type(proto::DT_VECTOR_FP32);
|
|
field2_pb->set_dimension(128);
|
|
|
|
auto collection_schema = ProtoConverter::FromPb(schema_pb);
|
|
ASSERT_NE(collection_schema, nullptr);
|
|
EXPECT_EQ(collection_schema->name(), "test_collection");
|
|
EXPECT_EQ(collection_schema->fields().size(), 2);
|
|
EXPECT_EQ(collection_schema->max_doc_count_per_segment(), 1000000u);
|
|
|
|
// Test conversion from C++ to protobuf
|
|
CollectionSchema original_schema;
|
|
original_schema.set_name("original_collection");
|
|
|
|
auto pb_result = ProtoConverter::ToPb(original_schema);
|
|
EXPECT_EQ(pb_result.name(), "original_collection");
|
|
}
|
|
|
|
TEST(ConverterTest, BlockMetaConversion) {
|
|
// Test conversion from protobuf to C++ BlockMeta
|
|
proto::BlockMeta meta_pb;
|
|
meta_pb.set_block_id(1);
|
|
meta_pb.set_block_type(proto::BT_SCALAR);
|
|
meta_pb.set_min_doc_id(100);
|
|
meta_pb.set_max_doc_id(200);
|
|
meta_pb.set_doc_count(50);
|
|
meta_pb.add_columns("col1");
|
|
meta_pb.add_columns("col2");
|
|
|
|
auto block_meta = ProtoConverter::FromPb(meta_pb);
|
|
ASSERT_NE(block_meta, nullptr);
|
|
EXPECT_EQ(block_meta->id(), 1u);
|
|
EXPECT_EQ(block_meta->type(), BlockType::SCALAR);
|
|
EXPECT_EQ(block_meta->min_doc_id(), 100u);
|
|
EXPECT_EQ(block_meta->max_doc_id(), 200u);
|
|
EXPECT_EQ(block_meta->doc_count(), 50u);
|
|
EXPECT_EQ(block_meta->columns().size(), 2);
|
|
EXPECT_EQ(block_meta->columns()[0], "col1");
|
|
EXPECT_EQ(block_meta->columns()[1], "col2");
|
|
|
|
// Test conversion from C++ to protobuf
|
|
BlockMeta original_meta(2, BlockType::VECTOR_INDEX, 300, 400);
|
|
original_meta.set_doc_count(75);
|
|
original_meta.add_column("col3");
|
|
original_meta.add_column("col4");
|
|
|
|
auto pb_result = ProtoConverter::ToPb(original_meta);
|
|
EXPECT_EQ(pb_result.block_id(), 2u);
|
|
EXPECT_EQ(pb_result.block_type(), proto::BT_VECTOR_INDEX);
|
|
EXPECT_EQ(pb_result.min_doc_id(), 300u);
|
|
EXPECT_EQ(pb_result.max_doc_id(), 400u);
|
|
EXPECT_EQ(pb_result.doc_count(), 75u);
|
|
EXPECT_EQ(pb_result.columns_size(), 2);
|
|
EXPECT_EQ(pb_result.columns(0), "col3");
|
|
EXPECT_EQ(pb_result.columns(1), "col4");
|
|
}
|
|
|
|
TEST(ConverterTest, SegmentMetaConversion) {
|
|
// Test conversion from protobuf to C++ SegmentMeta
|
|
proto::SegmentMeta segment_pb;
|
|
segment_pb.set_segment_id(10);
|
|
|
|
// Add persisted blocks
|
|
auto *block1_pb = segment_pb.add_persisted_blocks();
|
|
block1_pb->set_block_id(1);
|
|
block1_pb->set_block_type(proto::BT_SCALAR);
|
|
block1_pb->set_min_doc_id(0);
|
|
block1_pb->set_max_doc_id(100);
|
|
block1_pb->set_doc_count(50);
|
|
block1_pb->add_columns("col1");
|
|
block1_pb->add_columns("col2");
|
|
|
|
auto *block2_pb = segment_pb.add_persisted_blocks();
|
|
block2_pb->set_block_id(2);
|
|
block2_pb->set_block_type(proto::BT_VECTOR_INDEX);
|
|
block2_pb->set_min_doc_id(101);
|
|
block2_pb->set_max_doc_id(200);
|
|
block2_pb->set_doc_count(75);
|
|
block2_pb->add_columns("vec_col");
|
|
|
|
// Add writing forward block
|
|
auto *writing_block_pb = segment_pb.mutable_writing_forward_block();
|
|
writing_block_pb->set_block_id(3);
|
|
writing_block_pb->set_block_type(proto::BT_SCALAR);
|
|
writing_block_pb->set_min_doc_id(201);
|
|
writing_block_pb->set_max_doc_id(300);
|
|
writing_block_pb->set_doc_count(25);
|
|
writing_block_pb->add_columns("col3");
|
|
|
|
// Add indexed vector fields
|
|
segment_pb.add_indexed_vector_fields("vec_col1");
|
|
segment_pb.add_indexed_vector_fields("vec_col2");
|
|
|
|
auto segment_meta = ProtoConverter::FromPb(segment_pb);
|
|
ASSERT_NE(segment_meta, nullptr);
|
|
EXPECT_EQ(segment_meta->id(), 10u);
|
|
EXPECT_EQ(segment_meta->persisted_blocks().size(), 2);
|
|
EXPECT_TRUE(segment_meta->has_writing_forward_block());
|
|
|
|
// Check first persisted block
|
|
const auto &block1 = segment_meta->persisted_blocks()[0];
|
|
EXPECT_EQ(block1.id(), 1u);
|
|
EXPECT_EQ(block1.type(), BlockType::SCALAR);
|
|
EXPECT_EQ(block1.min_doc_id(), 0u);
|
|
EXPECT_EQ(block1.max_doc_id(), 100u);
|
|
EXPECT_EQ(block1.doc_count(), 50u);
|
|
EXPECT_EQ(block1.columns().size(), 2);
|
|
EXPECT_EQ(block1.columns()[0], "col1");
|
|
EXPECT_EQ(block1.columns()[1], "col2");
|
|
|
|
// Check second persisted block
|
|
const auto &block2 = segment_meta->persisted_blocks()[1];
|
|
EXPECT_EQ(block2.id(), 2u);
|
|
EXPECT_EQ(block2.type(), BlockType::VECTOR_INDEX);
|
|
EXPECT_EQ(block2.min_doc_id(), 101u);
|
|
EXPECT_EQ(block2.max_doc_id(), 200u);
|
|
EXPECT_EQ(block2.doc_count(), 75u);
|
|
EXPECT_EQ(block2.columns().size(), 1);
|
|
EXPECT_EQ(block2.columns()[0], "vec_col");
|
|
|
|
// Check writing forward block
|
|
const auto &writing_block = segment_meta->writing_forward_block();
|
|
EXPECT_EQ(writing_block.value().id(), 3u);
|
|
EXPECT_EQ(writing_block.value().type(), BlockType::SCALAR);
|
|
EXPECT_EQ(writing_block.value().min_doc_id(), 201u);
|
|
EXPECT_EQ(writing_block.value().max_doc_id(), 300u);
|
|
EXPECT_EQ(writing_block.value().doc_count(), 25u);
|
|
EXPECT_EQ(writing_block.value().columns().size(), 1);
|
|
EXPECT_EQ(writing_block.value().columns()[0], "col3");
|
|
|
|
// Check indexed vector fields
|
|
EXPECT_TRUE(segment_meta->vector_indexed("vec_col1"));
|
|
EXPECT_TRUE(segment_meta->vector_indexed("vec_col2"));
|
|
EXPECT_FALSE(segment_meta->vector_indexed("non_existent_field"));
|
|
|
|
// Test conversion from C++ to protobuf
|
|
SegmentMeta original_meta(20);
|
|
|
|
// Add persisted blocks
|
|
BlockMeta block1_meta(1, BlockType::SCALAR_INDEX, 0, 50);
|
|
block1_meta.set_doc_count(25);
|
|
block1_meta.add_column("col3");
|
|
block1_meta.add_column("col4");
|
|
original_meta.add_persisted_block(block1_meta);
|
|
|
|
BlockMeta block2_meta(2, BlockType::VECTOR_INDEX_QUANTIZE, 51, 100);
|
|
block2_meta.set_doc_count(30);
|
|
block2_meta.add_column("vec_col2");
|
|
original_meta.add_persisted_block(block2_meta);
|
|
|
|
// Set writing forward block
|
|
BlockMeta writing_block_meta(3, BlockType::SCALAR, 101, 150);
|
|
writing_block_meta.set_doc_count(40);
|
|
writing_block_meta.add_column("col5");
|
|
original_meta.set_writing_forward_block(writing_block_meta);
|
|
|
|
// Add indexed vector fields
|
|
original_meta.add_indexed_vector_field("vec_field1");
|
|
original_meta.add_indexed_vector_field("vec_field2");
|
|
|
|
auto pb_result = ProtoConverter::ToPb(original_meta);
|
|
EXPECT_EQ(pb_result.segment_id(), 20u);
|
|
EXPECT_EQ(pb_result.persisted_blocks_size(), 2);
|
|
|
|
// Check first persisted block
|
|
const auto &pb_block1 = pb_result.persisted_blocks(0);
|
|
EXPECT_EQ(pb_block1.block_id(), 1u);
|
|
EXPECT_EQ(pb_block1.block_type(), proto::BT_SCALAR_INDEX);
|
|
EXPECT_EQ(pb_block1.min_doc_id(), 0u);
|
|
EXPECT_EQ(pb_block1.max_doc_id(), 50u);
|
|
EXPECT_EQ(pb_block1.doc_count(), 25u);
|
|
EXPECT_EQ(pb_block1.columns_size(), 2);
|
|
EXPECT_EQ(pb_block1.columns(0), "col3");
|
|
EXPECT_EQ(pb_block1.columns(1), "col4");
|
|
|
|
// Check second persisted block
|
|
const auto &pb_block2 = pb_result.persisted_blocks(1);
|
|
EXPECT_EQ(pb_block2.block_id(), 2u);
|
|
EXPECT_EQ(pb_block2.block_type(), proto::BT_VECTOR_INDEX_QUANTIZE);
|
|
EXPECT_EQ(pb_block2.min_doc_id(), 51u);
|
|
EXPECT_EQ(pb_block2.max_doc_id(), 100u);
|
|
EXPECT_EQ(pb_block2.doc_count(), 30u);
|
|
EXPECT_EQ(pb_block2.columns_size(), 1);
|
|
EXPECT_EQ(pb_block2.columns(0), "vec_col2");
|
|
|
|
// Check writing forward block
|
|
const auto &pb_writing_block = pb_result.writing_forward_block();
|
|
EXPECT_EQ(pb_writing_block.block_id(), 3u);
|
|
EXPECT_EQ(pb_writing_block.block_type(), proto::BT_SCALAR);
|
|
EXPECT_EQ(pb_writing_block.min_doc_id(), 101u);
|
|
EXPECT_EQ(pb_writing_block.max_doc_id(), 150u);
|
|
EXPECT_EQ(pb_writing_block.doc_count(), 40u);
|
|
EXPECT_EQ(pb_writing_block.columns_size(), 1);
|
|
EXPECT_EQ(pb_writing_block.columns(0), "col5");
|
|
|
|
// Check indexed vector fields
|
|
EXPECT_EQ(pb_result.indexed_vector_fields_size(), 2);
|
|
EXPECT_EQ(pb_result.indexed_vector_fields(0), "vec_field1");
|
|
EXPECT_EQ(pb_result.indexed_vector_fields(1), "vec_field2");
|
|
}
|
|
|
|
TEST(ConverterTest, SegmentMetaWithEmptyFields) {
|
|
// Test conversion with minimal data
|
|
proto::SegmentMeta segment_pb;
|
|
segment_pb.set_segment_id(1);
|
|
|
|
auto segment_meta = ProtoConverter::FromPb(segment_pb);
|
|
ASSERT_NE(segment_meta, nullptr);
|
|
EXPECT_EQ(segment_meta->id(), 1u);
|
|
EXPECT_EQ(segment_meta->persisted_blocks().size(), 0);
|
|
EXPECT_FALSE(segment_meta->has_writing_forward_block());
|
|
EXPECT_EQ(segment_meta->indexed_vector_fields().size(), 0);
|
|
|
|
// Test conversion from C++ to protobuf with minimal data
|
|
SegmentMeta original_meta(5);
|
|
auto pb_result = ProtoConverter::ToPb(original_meta);
|
|
EXPECT_EQ(pb_result.segment_id(), 5u);
|
|
EXPECT_EQ(pb_result.persisted_blocks_size(), 0);
|
|
EXPECT_FALSE(pb_result.has_writing_forward_block());
|
|
EXPECT_EQ(pb_result.indexed_vector_fields_size(), 0);
|
|
}
|
|
|
|
// ==================== enable_rotate roundtrip tests ====================
|
|
|
|
TEST(ConverterTest, HnswIndexParamsWithEnableRotate) {
|
|
// C++ -> PB -> C++ roundtrip with enable_rotate = true
|
|
HnswIndexParams original(MetricType::COSINE, 16, 200, QuantizeType::INT8,
|
|
false, QuantizerParam(true));
|
|
EXPECT_TRUE(original.quantizer_param().enable_rotate());
|
|
|
|
auto pb = ProtoConverter::ToPb(&original);
|
|
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
|
|
|
|
auto restored = ProtoConverter::FromPb(pb);
|
|
ASSERT_NE(restored, nullptr);
|
|
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
|
|
EXPECT_TRUE(restored->enable_rotate()); // convenience getter
|
|
EXPECT_EQ(restored->metric_type(), MetricType::COSINE);
|
|
EXPECT_EQ(restored->m(), 16);
|
|
EXPECT_EQ(restored->ef_construction(), 200);
|
|
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
|
|
|
|
// C++ -> PB -> C++ roundtrip with enable_rotate = false
|
|
HnswIndexParams original_no_rot(MetricType::L2, 32, 100, QuantizeType::FP16);
|
|
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
|
|
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
|
|
auto restored2 = ProtoConverter::FromPb(pb2);
|
|
ASSERT_NE(restored2, nullptr);
|
|
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
|
|
}
|
|
|
|
TEST(ConverterTest, FlatIndexParamsWithEnableRotate) {
|
|
FlatIndexParams original(MetricType::IP, QuantizeType::INT8,
|
|
QuantizerParam(true));
|
|
EXPECT_TRUE(original.quantizer_param().enable_rotate());
|
|
|
|
auto pb = ProtoConverter::ToPb(&original);
|
|
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
|
|
|
|
auto restored = ProtoConverter::FromPb(pb);
|
|
ASSERT_NE(restored, nullptr);
|
|
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
|
|
EXPECT_EQ(restored->metric_type(), MetricType::IP);
|
|
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
|
|
|
|
// enable_rotate = false
|
|
FlatIndexParams original_no_rot(MetricType::L2, QuantizeType::FP16);
|
|
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
|
|
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
|
|
auto restored2 = ProtoConverter::FromPb(pb2);
|
|
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
|
|
}
|
|
|
|
TEST(ConverterTest, IVFIndexParamsWithEnableRotate) {
|
|
IVFIndexParams original(MetricType::COSINE, 256, 20, true, QuantizeType::INT8,
|
|
QuantizerParam(true));
|
|
EXPECT_TRUE(original.quantizer_param().enable_rotate());
|
|
|
|
auto pb = ProtoConverter::ToPb(&original);
|
|
EXPECT_TRUE(pb.base().quantizer_param().enable_rotate());
|
|
|
|
auto restored = ProtoConverter::FromPb(pb);
|
|
ASSERT_NE(restored, nullptr);
|
|
EXPECT_TRUE(restored->quantizer_param().enable_rotate());
|
|
EXPECT_EQ(restored->metric_type(), MetricType::COSINE);
|
|
EXPECT_EQ(restored->n_list(), 256);
|
|
EXPECT_EQ(restored->n_iters(), 20);
|
|
EXPECT_TRUE(restored->use_soar());
|
|
EXPECT_EQ(restored->quantize_type(), QuantizeType::INT8);
|
|
|
|
// enable_rotate = false
|
|
IVFIndexParams original_no_rot(MetricType::L2, 128, 10, false,
|
|
QuantizeType::FP16);
|
|
auto pb2 = ProtoConverter::ToPb(&original_no_rot);
|
|
EXPECT_FALSE(pb2.base().quantizer_param().enable_rotate());
|
|
auto restored2 = ProtoConverter::FromPb(pb2);
|
|
EXPECT_FALSE(restored2->quantizer_param().enable_rotate());
|
|
} |