mirror of
https://github.com/milvus-io/milvus.git
synced 2026-07-21 02:05:41 +00:00
fix: prevent growing element-level filter from reading past active rows (#50467)
issue: https://github.com/milvus-io/milvus/issues/50333 ref: https://github.com/milvus-io/milvus/issues/42148 Signed-off-by: SpadeA <tangchenjie1210@gmail.com>
This commit is contained in:
@@ -958,10 +958,20 @@ class SegmentExpr : public Expr {
|
||||
for (size_t i = current_data_chunk_; i < num_data_chunk_; i++) {
|
||||
auto data_pos =
|
||||
i == current_data_chunk_ ? current_data_chunk_pos_ : 0;
|
||||
int64_t size = segment_->chunk_size(field_id_, i) - data_pos;
|
||||
int64_t size;
|
||||
if (segment_->is_chunked()) {
|
||||
size = segment_->chunk_size(field_id_, i) - data_pos;
|
||||
} else {
|
||||
size = (i == num_data_chunk_ - 1)
|
||||
? (active_count_ % size_per_chunk_ == 0
|
||||
? size_per_chunk_ - data_pos
|
||||
: active_count_ % size_per_chunk_ - data_pos)
|
||||
: size_per_chunk_ - data_pos;
|
||||
}
|
||||
size = std::min(size, batch_size_ - processed_rows);
|
||||
if (size == 0)
|
||||
if (size <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& skip_index = segment_->GetSkipIndex();
|
||||
if ((!skip_func || !skip_func(skip_index, field_id_, i))) {
|
||||
|
||||
@@ -2249,6 +2249,101 @@ TEST_P(ElementFilterEmptyDocHit, ActiveDocsWithZeroElements) {
|
||||
ASSERT_EQ(retrieve_results->offset_size(), 0);
|
||||
}
|
||||
|
||||
TEST(ElementFilter, GrowingNullableArrayTailChunkUsesActiveRows) {
|
||||
auto schema = std::make_shared<Schema>();
|
||||
auto int_array_fid = schema->AddDebugArrayField(
|
||||
"structA[price_array]", DataType::INT32, true);
|
||||
auto int64_fid = schema->AddDebugField("id", DataType::INT64);
|
||||
schema->set_primary_field_id(int64_fid);
|
||||
|
||||
SegcoreConfig config;
|
||||
config.set_chunk_rows(1024);
|
||||
auto segment = CreateGrowingSegment(schema, empty_index_meta, 1, config);
|
||||
|
||||
auto insert_record_proto = std::make_unique<InsertRecordProto>();
|
||||
insert_record_proto->set_num_rows(3);
|
||||
|
||||
auto pk_data = insert_record_proto->add_fields_data();
|
||||
pk_data->set_field_id(int64_fid.get());
|
||||
pk_data->set_type(proto::schema::DataType::Int64);
|
||||
pk_data->mutable_scalars()->mutable_long_data()->add_data(0);
|
||||
pk_data->mutable_scalars()->mutable_long_data()->add_data(1);
|
||||
pk_data->mutable_scalars()->mutable_long_data()->add_data(2);
|
||||
|
||||
auto array_data = insert_record_proto->add_fields_data();
|
||||
array_data->set_field_id(int_array_fid.get());
|
||||
array_data->set_type(proto::schema::DataType::Array);
|
||||
array_data->add_valid_data(true);
|
||||
array_data->add_valid_data(false);
|
||||
array_data->add_valid_data(true);
|
||||
auto arrays = array_data->mutable_scalars()->mutable_array_data();
|
||||
arrays->set_element_type(proto::schema::DataType::Int32);
|
||||
auto row0 = arrays->mutable_data()->Add();
|
||||
row0->mutable_int_data()->mutable_data()->Add(10);
|
||||
row0->mutable_int_data()->mutable_data()->Add(11);
|
||||
auto row1 = arrays->mutable_data()->Add();
|
||||
row1->mutable_int_data();
|
||||
auto row2 = arrays->mutable_data()->Add();
|
||||
row2->mutable_int_data()->mutable_data()->Add(20);
|
||||
|
||||
std::vector<int64_t> row_ids = {0, 1, 2};
|
||||
std::vector<Timestamp> timestamps = {100, 101, 102};
|
||||
auto offset = segment->PreInsert(3);
|
||||
segment->Insert(offset,
|
||||
3,
|
||||
row_ids.data(),
|
||||
timestamps.data(),
|
||||
insert_record_proto.get());
|
||||
|
||||
proto::plan::PlanNode plan_node;
|
||||
auto* query = plan_node.mutable_query();
|
||||
query->set_is_count(false);
|
||||
query->set_limit(10);
|
||||
|
||||
auto* element_filter =
|
||||
query->mutable_predicates()->mutable_element_filter_expr();
|
||||
element_filter->set_struct_name("structA");
|
||||
|
||||
auto* element_expr = element_filter->mutable_element_expr();
|
||||
auto* elem_range = element_expr->mutable_unary_range_expr();
|
||||
auto* elem_col = elem_range->mutable_column_info();
|
||||
elem_col->set_field_id(int_array_fid.get());
|
||||
elem_col->set_data_type(proto::schema::DataType::Int32);
|
||||
elem_col->set_element_type(proto::schema::DataType::Int32);
|
||||
elem_col->set_is_element_level(true);
|
||||
elem_range->set_op(proto::plan::OpType::GreaterEqual);
|
||||
elem_range->mutable_value()->set_int64_val(0);
|
||||
|
||||
plan_node.add_output_field_ids(int64_fid.get());
|
||||
plan_node.add_output_field_ids(int_array_fid.get());
|
||||
|
||||
auto parser = ProtoParser(schema);
|
||||
auto plan = parser.CreateRetrievePlan(plan_node);
|
||||
|
||||
std::unique_ptr<proto::segcore::RetrieveResults> retrieve_results;
|
||||
ASSERT_NO_THROW({
|
||||
retrieve_results = segment->Retrieve(nullptr,
|
||||
plan.get(),
|
||||
1L << 63,
|
||||
INT64_MAX,
|
||||
false,
|
||||
folly::CancellationToken(),
|
||||
0,
|
||||
0);
|
||||
});
|
||||
|
||||
ASSERT_NE(retrieve_results, nullptr);
|
||||
ASSERT_TRUE(retrieve_results->element_level());
|
||||
ASSERT_EQ(retrieve_results->offset_size(), 2);
|
||||
EXPECT_EQ(retrieve_results->offset(0), 0);
|
||||
ASSERT_EQ(retrieve_results->element_indices(0).indices_size(), 2);
|
||||
EXPECT_EQ(retrieve_results->element_indices(0).indices(0), 0);
|
||||
EXPECT_EQ(retrieve_results->element_indices(0).indices(1), 1);
|
||||
EXPECT_EQ(retrieve_results->offset(1), 2);
|
||||
ASSERT_EQ(retrieve_results->element_indices(1).indices_size(), 1);
|
||||
EXPECT_EQ(retrieve_results->element_indices(1).indices(0), 0);
|
||||
}
|
||||
|
||||
TEST_P(ElementFilterEmptyDocHit, ElementLevelSearchWithZeroElements) {
|
||||
bool with_sealed = GetParam();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user