JingsongLi commented on code in PR #9550:
URL: https://github.com/apache/paimon/pull/9550#discussion_r3986953094


##########
paimon-format/src/main/java/org/apache/paimon/format/parquet/reader/ParquetReaderUtil.java:
##########
@@ -163,34 +173,26 @@ private static ParquetField constructField(
                     type instanceof ArrayType
                             ? ((ArrayType) type).getElementType()
                             : ((VectorType) type).getElementType();
-            ColumnIO elementTypeColumnIO;
-            if (columnIO instanceof GroupColumnIO) {
-                GroupColumnIO groupColumnIO = (GroupColumnIO) columnIO;
-                if (!StringUtils.isNullOrWhitespaceOnly(fieldName)) {
-                    // Column lookup is case-insensitive; the wrapper-group 
names can
-                    // therefore differ in case from the requested field name.
-                    while 
(!groupColumnIO.getName().equalsIgnoreCase(fieldName)) {
-                        groupColumnIO = (GroupColumnIO) 
groupColumnIO.getChild(0);
-                    }
-                    elementTypeColumnIO = groupColumnIO;
-                } else {
-                    if (elementType instanceof RowType) {
-                        elementTypeColumnIO = groupColumnIO;
-                    } else {
-                        elementTypeColumnIO = groupColumnIO.getChild(0);
-                    }
-                }
-            } else if (columnIO instanceof PrimitiveColumnIO) {
-                elementTypeColumnIO = columnIO;
-            } else {
-                throw new RuntimeException(String.format("Unknown ColumnIO, 
%s", columnIO));
-            }
+            GroupColumnIO groupColumnIO = (GroupColumnIO) columnIO;
+            GroupType requestedGroup = parquetType.asGroupType();
+
+            boolean threeLevel =
+                    listLayout.isThreeLevelList(requestedGroup, 
groupColumnIO.getFieldPath());

Review Comment:
   [P2] Use the original LIST layout when inferring fallback fields too
   
   Reading a newly added nested field can now fail during reader construction. 
For a file containing `s.a: ARRAY<ROW<x INT, y INT>>` encoded with Rule 2, 
reading only `s.newField` enters the all-fields-missing fallback. 
`findCheapestGroupField` retains `a.element.x` to preserve whether `s` is null, 
and the extra-field loop above infers that clipped schema as `ARRAY<INT>`. 
However, this lookup remembers that the original list element was a struct, so 
`constructField` receives a `GroupColumnIO` for the inferred primitive and 
throws `ClassCastException`.
   
   I reproduced this with an actual three-row Parquet file, including a null 
parent and an empty list: the baseline reader implementation passes, while this 
head fails at `ParquetReaderUtil.java:208`. Please make fallback-field type 
inference use the original layout as well, or preserve its logical element type 
during pruning, and add an end-to-end missing-nested-field projection test.



##########
paimon-format/src/main/java/org/apache/paimon/format/parquet/ParquetSchemaConverter.java:
##########
@@ -462,10 +462,18 @@ public static DataField convertToPaimonField(Type 
parquetType) {
                     parquetType.getId().intValue(), parquetType.getName(), 
paimonDataType);
         } else {
             GroupType groupType = parquetType.asGroupType();
-            if (logicalType instanceof 
LogicalTypeAnnotation.ListLogicalTypeAnnotation) {
+            if (ParquetListLayoutResolver.isList(groupType)) {
+                Type parquetElementType = 
ParquetListLayoutResolver.resolveElementType(groupType);
+                DataType elementDataType = 
convertToPaimonField(parquetElementType).type();
+                if (!ParquetListLayoutResolver.isThreeLevelList(groupType)) {
+                    // Rules 1-4: the repeated node itself is the element. A 
REPEATED node is
+                    // never null, so the element type is not nullable.
+                    elementDataType = elementDataType.notNull();
+                }
+                paimonDataType = new ArrayType(elementDataType);
+            } else if 
(ParquetListLayoutResolver.isLegacyNestedList(groupType)) {
                 paimonDataType =
-                        new ArrayType(
-                                
convertToPaimonField(parquetListElementType(groupType)).type());
+                        new 
ArrayType(convertToPaimonField(groupType.getType(0)).type().notNull());

Review Comment:
   [P2] Preserve MAP annotations before applying legacy nested-list inference
   
   `isLegacyNestedList` also matches a repeated MAP group containing its single 
repeated `key_value` child. Because this branch precedes the MAP branch, a 
legacy list with this shape is inferred as `ARRAY<ARRAY<ROW<key, value>>>` 
instead of `ARRAY<MAP<STRING, INT>>`:
   
   ```text
   optional group my_list (LIST) {
     repeated group array (MAP) {
       repeated group key_value {
         required binary key (STRING);
         optional int32 value;
       }
     }
   }
   ```
   
   This is produced by [parquet-avro's old LIST 
encoding](https://github.com/apache/parquet-java/blob/master/parquet-avro/src/main/java/org/apache/parquet/avro/AvroSchemaConverter.java#L218-L234):
 it converts array elements with `REPEATED` repetition and preserves that 
repetition for MAP elements. A converter probe confirms that the MAP node 
itself converted to `MapType` on the baseline and now converts to `ArrayType`. 
Whole-list inference was already incorrect on the baseline, so this is a gap in 
the new compatibility handling, rather than a claim that these complete files 
previously inferred correctly.
   
   Please handle MAP annotations before this fallback, or restrict the fallback 
to unannotated groups, and add an inference test for an array of maps using the 
old Avro LIST layout.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to