vin*_*bie 3 c++ parquet apache-arrow python-polars
我正在尝试使用 C++ 读取包含浮点数列表的镶木地板文件中的数据。
\n我使用以下 python 代码生成了一个简单的镶木地板文件:
\nimport polars as pl\nimport struct\nimport random\nimport pyarrow.parquet as pq\n\nfloatlist = []\nfor _ in range(10):\n lstlen = random.choice([3, 4, 5])\n floatlist.append([random.random() for _ in range(lstlen)])\n\ndf = pl.DataFrame({"float_list": floatlist})\n\nfile_out_path = \'test.parquet\'\ndf.write_parquet(file_out_path)\nprint(pl.read_parquet(file_out_path))\nRun Code Online (Sandbox Code Playgroud)\n结果看起来非常合理:
\nshape: (10, 1)\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 float_list \xe2\x94\x82\n\xe2\x94\x82 --- \xe2\x94\x82\n\xe2\x94\x82 list[f64] \xe2\x94\x82\n\xe2\x95\x9e\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa1\n\xe2\x94\x82 [0.863913, 0.831073, 0.264516] \xe2\x94\x82\n\xe2\x94\x82 [0.51377, 0.434267, \xe2\x80\xa6 0.131684] \xe2\x94\x82\n\xe2\x94\x82 [0.978071, 0.251396, \xe2\x80\xa6 0.142218] \xe2\x94\x82\n\xe2\x94\x82 [0.495616, 0.628793, 0.434872] \xe2\x94\x82\n\xe2\x94\x82 \xe2\x80\xa6 \xe2\x94\x82\n\xe2\x94\x82 [0.19035, 0.68318, \xe2\x80\xa6 0.778707] \xe2\x94\x82\n\xe2\x94\x82 [0.103636, 0.08755, \xe2\x80\xa6 0.526014] \xe2\x94\x82\n\xe2\x94\x82 [0.803863, 0.382698, \xe2\x80\xa6 0.728598] \xe2\x94\x82\n\xe2\x94\x82 [0.323969, 0.412751, \xe2\x80\xa6 0.12993] \xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98\n\nRun Code Online (Sandbox Code Playgroud)\n现在我尝试使用以下代码在 C++ 中读取相同的 test.parquet 文件:
\nvoid read_parquet(std::string file_name) {\n\n arrow::Status st;\n std::shared_ptr<arrow::io::ReadableFile> infile;\n\n PARQUET_ASSIGN_OR_THROW(infile, arrow::io::ReadableFile::Open(file_name));\n\n std::unique_ptr<parquet::arrow::FileReader> reader;\n PARQUET_THROW_NOT_OK(parquet::arrow::OpenFile(infile, arrow::default_memory_pool(), &reader));\n\n std::shared_ptr<arrow::RecordBatchReader> record_batch_reader;\n st = reader->GetRecordBatchReader(&record_batch_reader);\n std::shared_ptr<arrow::RecordBatch> record_batch;\n\n while (true) {\n arrow::Status status = record_batch_reader->ReadNext(&record_batch);\n\n if (!status.ok() || record_batch == nullptr) {\n break; // Exit the loop if there are no more batches or if an error occurs\n }\n\n std::cout << "Num records in batch: " << record_batch->num_rows() << std::endl;\n auto floatlist = std::static_pointer_cast<arrow::ListArray>(record_batch->column(0));\n std::cout << "Length of floatlist: " << floatlist->length() << std::endl;\n std::cout << "Offsets: " << floatlist->offsets()->ToString() << std::endl;\n \n auto floatlist_vals = std::static_pointer_cast<arrow::DoubleArray>(floatlist->values());\n const double* floatlist_ptr = floatlist_vals->raw_values();\n\n for (int64_t i = 0; i < record_batch->num_rows(); i++) {\n\n std::cout << "\\n\\n";\n\n if ( floatlist->IsValid(i) ) {\n std::cout << "Row " << i << " IsValid" << std::endl;\n }\n if ( floatlist->IsNull(i) ) {\n std::cout << "Row " << i << " IsNull" << std::endl;\n }\n \n const double* first = floatlist_ptr + floatlist->value_offset(2*i);\n const double* last = floatlist_ptr + floatlist->value_offset(2*(i + 1));\n if (last > first) {\n std::vector<double> flst(first, last);\n std::cout << "Length of flst is: " << flst.size() << std::endl;\n for (size_t i = 0; i < flst.size(); i++) {\n std::cout << flst[i] << ", ";\n }\n std::cout << std::endl;\n }\n }\n }\n}\n\nRun Code Online (Sandbox Code Playgroud)\n我发现的是:
\nstd::cout << "Offsets: " << floatlist->offsets()->ToString() << std::endl;\nRun Code Online (Sandbox Code Playgroud)\n生成以下输出:
\nOffsets: [\n 0,\n 0,\n 3,\n 0,\n 7,\n 0,\n 12,\n 0,\n 15,\n 0,\n 19\n]\n\nRun Code Online (Sandbox Code Playgroud)\n一些示例表明我可以使用以下方法恢复数据:
\nconst double* first = floatlist_ptr + floatlist->value_offset(i);\nconst double* last = floatlist_ptr + floatlist->value_offset(i + 1);\nstd::vector<double> flst(first, last);\nRun Code Online (Sandbox Code Playgroud)\n但由于 value_offsets 列表中的零,这显然会崩溃。\n我可以使用以下命令使其工作:
\nconst double* first = floatlist_ptr + floatlist->value_offset(2*i);\nconst double* last = floatlist_ptr + floatlist->value_offset(2*(i + 1));\nif (last > first) {\n std::vector<double> flst(first, last);\n}\n\nRun Code Online (Sandbox Code Playgroud)\n我的问题:
\n为什么偏移量列表中散布着零?
\n为什么我们会认为偏移量是num_rows + 1,但实际上
\narrow::BaseListArray<arrow::ListType>::value_offset(int64_t i)\nRun Code Online (Sandbox Code Playgroud)\n接受远高于 num_rows + 1 的索引值。事实上,您至少需要达到 2*num_rows 才能获取所有数据?
\nPola.rs 默认以Type::LARGE_LIST物理方式表示逻辑列表类型,因此当您从 Pola.rs 写入的文件中获取数据时,您应该将其转换LargeListArray为ListArray.
您看到的零是 64 位偏移量的额外 32 位一半,可以适合 32 位偏移量。
要对强制转换进行调试构建检查,您可以在强制转换为 之前使用arrow::internal::checked_cast<T>或。assert(array.type_id() == arrow::Type::LIST_TYPE)ListArray
| 归档时间: |
|
| 查看次数: |
118 次 |
| 最近记录: |