Files
2026-07-13 12:47:42 +08:00

131 lines
3.7 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 "db/index/storage/arrow_ipc_writer.h"
#include <iostream>
#include <arrow/array/builder_primitive.h>
#include <arrow/ipc/reader.h>
#include <arrow/record_batch.h>
#include <arrow/status.h>
#include <gtest/gtest.h>
#include "db/index/storage/store_helper.h"
using namespace zvec;
auto schema = arrow::schema(
{arrow::field("id", arrow::int32()), arrow::field("name", arrow::utf8())});
std::shared_ptr<arrow::RecordBatchReader> CreateTestReader(int start_id,
int count) {
arrow::Int32Builder id_builder;
arrow::StringBuilder name_builder;
arrow::Status s;
for (int i = 0; i < count; ++i) {
s = id_builder.Append(start_id + i);
if (!s.ok()) {
return nullptr;
}
s = name_builder.Append("User" + std::to_string(start_id + i));
if (!s.ok()) {
return nullptr;
}
}
std::shared_ptr<arrow::Array> id_array, name_array;
s = id_builder.Finish(&id_array);
if (!s.ok()) {
return nullptr;
}
s = name_builder.Finish(&name_array);
if (!s.ok()) {
return nullptr;
}
auto batch = arrow::RecordBatch::Make(schema, count, {id_array, name_array});
auto maybe_reader = arrow::RecordBatchReader::Make({batch}, schema);
if (!maybe_reader.ok()) {
return nullptr;
}
return *maybe_reader;
}
TEST(ArrowIpcWriter, General) {
std::string output_file_path = "output.ipc";
ArrowIpcWriter writer(output_file_path);
// writer.SetMaxRowsPerGroup(1000); // 可选:控制每组行数
// 第一次插入
{
auto reader1 = CreateTestReader(1, 3);
ASSERT_NE(reader1, nullptr);
auto status = writer.insert(reader1);
ASSERT_TRUE(status.ok());
std::cout << "Inserted batch 1" << std::endl;
}
// 第二次插入
{
auto reader2 = CreateTestReader(4, 2);
ASSERT_NE(reader2, nullptr);
auto status = writer.insert(reader2);
ASSERT_TRUE(status.ok());
std::cout << "Inserted batch 2" << std::endl;
}
// 第三次插入
{
auto reader3 = CreateTestReader(6, 4);
ASSERT_NE(reader3, nullptr);
auto status = writer.insert(reader3);
ASSERT_TRUE(status.ok());
std::cout << "Inserted batch 3" << std::endl;
}
// 最后关闭文件
auto status = writer.finalize();
if (!status.ok()) {
std::cerr << "Finalize failed: " << status.ToString() << std::endl;
}
std::cout << "Parquet file written successfully to output.parquet"
<< std::endl;
// 读取文件
std::shared_ptr<arrow::io::RandomAccessFile> output_file_;
std::string output_file_path_cp;
auto as = CreateRandomAccessFileByUri(output_file_path, &output_file_,
&output_file_path_cp);
ASSERT_TRUE(as.ok());
auto result = arrow::ipc::RecordBatchFileReader::Open(output_file_);
ASSERT_TRUE(result.ok());
auto reader = std::move(result).ValueOrDie();
ASSERT_EQ(reader->num_record_batches(), 3);
int num_rows = 0;
for (int i = 0; i < reader->num_record_batches(); i++) {
std::shared_ptr<arrow::RecordBatch> batch;
auto res = reader->ReadRecordBatch(i);
ASSERT_TRUE(res.ok());
batch = std::move(res).ValueOrDie();
num_rows += batch->num_rows();
}
ASSERT_EQ(num_rows, 9);
}