Skip to content

feat: support fixed-size arrays in data readers#726

Merged
shirly121 merged 12 commits into
alibaba:mainfrom
shirly121:impl_array_parser
Jul 22, 2026
Merged

feat: support fixed-size arrays in data readers#726
shirly121 merged 12 commits into
alibaba:mainfrom
shirly121:impl_array_parser

Conversation

@shirly121

@shirly121 shirly121 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • support parsing explicitly typed fixed-size arrays from CSV LOAD FROM, including nested arrays, quoted strings, temporal values, and length validation
  • support fixed-size array values in the JSON reader and when materializing COPY FROM results into graph properties
  • support Arrow FIXED_SIZE_LIST columns in the Parquet reader, including nested arrays and scalar child types
  • add end-to-end CSV, JSON, and Parquet array coverage and document the explicit CAST(..., T[N]) workflow

Variable-length LIST types such as FLOAT[] remain unsupported by these readers. Users must explicitly specify a fixed-size array type such as FLOAT[3]; implicit LIST-to-ARRAY conversion is not performed.

Testing

  • python3 -m pytest -q tools/python_bind/tests/test_load_array.py — 15 passed

Fixes #441
Fixes #442
Fixes #443

Comment thread doc/source/data_io/import_data.md Outdated
| `escaping` | bool | `true` | Whether to enable escape character processing |

> **Array limitation:** `COPY FROM` CSV currently does not auto-detect or directly materialize fixed-size `ARRAY` columns from bracketed CSV fields such as `"[1,2,3]"`. Use Cypher literals/parameters for array properties, or a typed non-CSV ingestion path when available.
Since NeuG v0.1.3, `COPY FROM` supports loading `ARRAY` data from CSV,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Do we supported nested Arrays?
  2. What is the expected format of string, to be parsed into a array? is there any best practices from other database systems?

@shirly121 shirly121 Jul 22, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

支持嵌套数组;string 数组的格式就是 '[1, 2, 3]' or '[[1, 2, 3]]' ,json/parquet 直接复用他们自己的数组类型

Comment thread extension/parquet/src/arrow_column.cc Outdated
static_cast<const arrow::Date32Array&>(array).Value(index));
return Value::DATE(date);
}
case arrow::Type::DATE64:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] DATE64 construction may be incorrect

// DATE32: explicitly converts days since epoch
case arrow::Type::DATE32: {
    Date date;
    date.from_num_days(
        static_cast<const arrow::Date32Array&>(array).Value(index));
    return Value::DATE(date);
}
// DATE64: passes milliseconds directly to Date constructor
case arrow::Type::DATE64:
    return Value::DATE(
        Date(static_cast<const arrow::Date64Array&>(array).Value(index)));

Date32Array::Value() returns days since epoch; Date64Array::Value() returns milliseconds since epoch. The DATE32 path correctly uses from_num_days(), but DATE64 passes raw milliseconds to the Date constructor. If the constructor expects days (not milliseconds), this produces a date far in the future.

Suggestion: Verify the Date constructor's parameter semantics. If it expects days, convert: date.from_num_days(value / 86400000). If it expects milliseconds, add a comment clarifying the difference from DATE32.

Comment thread extension/parquet/src/arrow_column.cc Outdated
for (int64_t i = 0; i < array->length(); ++i) {
if (array->IsNull(i)) {
THROW_NOT_SUPPORTED_EXCEPTION(
"Null Parquet ARRAY values are not supported");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] Null Parquet ARRAY values throw instead of being skipped

if (array->IsNull(i)) {
    THROW_NOT_SUPPORTED_EXCEPTION(
        "Null Parquet ARRAY values are not supported");
}

CSV and JSON paths handle nulls via push_back_null(), but the Parquet path throws. If a Parquet file contains any null array values, the entire load fails. This inconsistency could surprise users.

Suggestion: Either use builder->push_back_null() for consistency with CSV/JSON, or document this limitation in the load_data / import_data docs.


namespace neug {

static DataType arrow_type_to_neug_type(const arrow::DataType& type) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] arrow_type_to_neug_type and arrow_value_at are parallel switch-cases

Both functions (~50 lines each) manually map every Arrow type to a NeuG type or Value. Adding a new Arrow type requires updating both functions, and it's easy to forget one.

Suggestion: Consider adding a comment like // When adding a new Arrow type, update both arrow_type_to_neug_type and arrow_value_at. to help future maintainers.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] arrow_type_to_neug_type and arrow_value_at are parallel switch-cases

Both functions (~50 lines each) manually map every Arrow type to a NeuG type or Value. Adding a new Arrow type requires updating both functions, and it's easy to forget one.

Suggestion: Consider adding a comment like // When adding a new Arrow type, update both arrow_type_to_neug_type and arrow_value_at. to help future maintainers.

all fixed in 486a112

Copilot AI review requested due to automatic review settings July 22, 2026 05:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR adds end-to-end support for explicitly typed fixed-size arrays (T[N]) across CSV/JSON/Parquet readers, including nested arrays and length validation, and updates docs + CI to cover the workflow.

Changes:

  • Add CSV parsing and property materialization support for fixed-size ARRAY values (including nested arrays).
  • Add JSON reader support for fixed-size ARRAY columns and unit tests.
  • Add Parquet (Arrow) FIXED_SIZE_LIST support and expand end-to-end test coverage + docs.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/python_bind/tests/test_load_array.py Adds comprehensive end-to-end tests for fixed-size array ingestion via CSV/JSON/Parquet.
tools/python_bind/tests/test_data_io_docs.py Updates doc-driven tests to reflect new explicit-cast array workflow.
tests/utils/json_test.cc Adds JSON reader unit test + helper for fixed-size array schema types.
src/utils/io/read/json/json_reader.cc Implements JSON array parsing into fixed-size NeuG ARRAY values with length validation.
src/storages/loader/loader_utils.cc Adds CSV array tokenization/parsing + wires array appender and property materialization.
src/storages/loader/csv_property_graph_loader.cc Switches schema type plumbing to pass full DataType (enables arrays) into CSV reader meta.
include/neug/storages/loader/loader_utils.h Updates reader-meta APIs to accept DataType instead of DataTypeId.
extension/parquet/src/arrow_column.cc Adds Arrow fixed-size list conversion + nested array cell materialization; improves date64 handling.
doc/source/data_io/load_data.md Documents explicit CAST(..., T[N]) workflow for arrays.
doc/source/data_io/import_data.md Documents COPY FROM (LOAD FROM ... CAST(..., T[N])) workflow for arrays.
.github/workflows/neug-extension-test.yml Adds Parquet array test invocation in extension workflow.
.github/workflows/build-and-test-common.yml Adds array tests to main CI pytest suite.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/build-and-test-common.yml
Comment thread .github/workflows/neug-extension-test.yml
Comment thread extension/parquet/src/arrow_column.cc
Comment thread extension/parquet/src/arrow_column.cc Outdated
Comment thread doc/source/data_io/load_data.md Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 05:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Comment thread .github/workflows/build-and-test-common.yml
Comment thread .github/workflows/neug-extension-test.yml
Comment thread extension/parquet/src/arrow_column.cc
Comment thread extension/parquet/src/arrow_column.cc Outdated
Comment thread tools/python_bind/tests/test_load_array.py Outdated
Comment thread tools/python_bind/tests/test_load_array.py Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 07:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 8 comments.

Comment thread .github/workflows/build-and-test-common.yml
Comment thread .github/workflows/neug-extension-test.yml
Comment thread extension/parquet/src/arrow_column.cc
Comment thread src/storages/loader/loader_utils.cc
Comment thread src/storages/loader/loader_utils.cc Outdated
Comment thread src/storages/loader/loader_utils.cc Outdated
Comment thread src/storages/loader/loader_utils.cc Outdated
Comment thread src/utils/io/read/json/json_reader.cc
Copilot AI review requested due to automatic review settings July 22, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Comment on lines 140 to 144
export FLEX_DATA_DIR=${GITHUB_WORKSPACE}/example_dataset/comprehensive_graph
GLOG_v=10 ${GITHUB_WORKSPACE}/build/tools/utils/bulk_loader -g ../../example_dataset/comprehensive_graph/graph.yaml -l ../../example_dataset/comprehensive_graph/import.yaml -d /tmp/comprehensive_graph
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_load.py -k "parquet or httpfs"
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_load_array.py -k "parquet"
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_export.py -k "parquet or httpfs"
Comment on lines 305 to 309
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_query.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_tp_service.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_load.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_load_array.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_export.py
Comment on lines +170 to +173
static std::shared_ptr<IContextColumn> convert_fixed_size_list_arrays(
const std::vector<std::shared_ptr<arrow::Array>>& arrays) {
const auto type = arrow_type_to_neug_type(*arrays.front()->type());
auto builder = ColumnsUtils::create_builder(type);
Comment on lines +49 to +52
NeuG supports reading `ARRAY` data from CSV, JSON,
and Parquet files. NeuG does not implicitly convert input values to `ARRAY`;
explicitly cast the column to a fixed-size `ARRAY` type in the `RETURN`
clause.
Comment on lines +243 to +246
`COPY FROM` supports loading `ARRAY` data from CSV,
JSON, and Parquet files. NeuG does not implicitly convert input values to
`ARRAY`; use `LOAD FROM` and explicitly cast the column to a fixed-size
`ARRAY` type.

@longbinlai longbinlai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copilot AI review requested due to automatic review settings July 22, 2026 08:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.

Comment on lines 140 to 144
export FLEX_DATA_DIR=${GITHUB_WORKSPACE}/example_dataset/comprehensive_graph
GLOG_v=10 ${GITHUB_WORKSPACE}/build/tools/utils/bulk_loader -g ../../example_dataset/comprehensive_graph/graph.yaml -l ../../example_dataset/comprehensive_graph/import.yaml -d /tmp/comprehensive_graph
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_load.py -k "parquet or httpfs"
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_load_array.py -k "parquet"
NEUG_RUN_EXTENSION_TESTS=true python3 -m pytest -sv tests/test_export.py -k "parquet or httpfs"
Comment on lines 305 to 310
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_query.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_tp_service.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_load.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_load_array.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_export.py
python3 -m pytest --cov=neug --cov-report=term --exitfirst --cov-append --cov-config=.coveragerc -sv tests/test_copy_temp.py
Comment on lines +29 to +42
static int64_t arrow_time_to_milliseconds(int64_t value,
arrow::TimeUnit::type unit) {
switch (unit) {
case arrow::TimeUnit::SECOND:
return value * Interval::MSECS_PER_SEC;
case arrow::TimeUnit::MILLI:
return value;
case arrow::TimeUnit::MICRO:
return value / Interval::MICROS_PER_MSEC;
case arrow::TimeUnit::NANO:
return value / (Interval::MICROS_PER_MSEC * 1000);
}
THROW_NOT_SUPPORTED_EXCEPTION("Unsupported Arrow time unit");
}
Comment on lines +170 to +176
static std::shared_ptr<IContextColumn> convert_fixed_size_list_arrays(
const std::vector<std::shared_ptr<arrow::Array>>& arrays) {
const auto type = arrow_type_to_neug_type(*arrays.front()->type());
auto builder = ColumnsUtils::create_builder(type);
size_t size = 0;
for (const auto& array : arrays) {
size += array->length();
@shirly121
shirly121 merged commit a67461f into alibaba:main Jul 22, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants