leaves12138 commented on code in PR #10461:
URL: https://github.com/apache/paimon/pull/10461#discussion_r4227844806


##########
paimon-python/pypaimon/write/native_write.py:
##########
@@ -39,11 +39,13 @@ def native_write_available() -> bool:
     return True
 
 
-def _native_partition_types_supported(schema, partition_keys):
+def _native_partition_types_supported(schema, partition_keys, 
legacy_partition_name=True):
     """Partition keys which Rust can encode and use to locate existing 
files."""
-    return not any(
+    # Java's legacy byte[].toString() contains an allocation identity, so 
binary
+    # partitions only have portable names with the cast-based option.
+    return not legacy_partition_name or not any(
         pa.types.is_binary(data_type) or pa.types.is_large_binary(data_type)
-        or pa.types.is_fixed_size_binary(data_type) or 
pa.types.is_floating(data_type)
+        or pa.types.is_fixed_size_binary(data_type)

Review Comment:
   [P2] Match Java non-finite names before enabling floating partitions
   
   Admitting FLOAT/DOUBLE to native IO exposes a mismatch in 
`_floating_partition_string()`: its non-finite branch returns Python `nan`, 
`inf`, and `-inf`, whereas both Rust and Java use `NaN`, `Infinity`, and 
`-Infinity`. I reproduced this with a DOUBLE-partitioned append table and 
`partition.legacy-name=false`: native write/commit succeeds, but a subsequent 
Python scan/read fails with `FileNotFoundError`, looking under `p=inf` while 
the actual file is under `p=Infinity`. NaN and negative infinity fail the same 
way; the finite controls succeed. `from_native_commit_messages()` also 
reconstructs the wrong `file_path`. Please handle these three spellings 
explicitly and add FLOAT/DOUBLE native-write/Python-read round trips; removing 
old directory probing is not the problem.



##########
paimon-python/pypaimon/write/file_store_commit.py:
##########
@@ -1087,31 +1087,18 @@ def _generate_partition_statistics(self, 
commit_entries: List[ManifestEntry]) ->
             List of PartitionStatistics for each unique partition
         """
         partition_stats = {}
+        path_factory = self.table.path_factory()
 
         for entry in commit_entries:
-            # Convert partition tuple to dictionary for PartitionStatistics
-            partition_value = tuple(entry.partition.values)  # Call the method 
to get partition value
-            if partition_value:
-                # Assuming partition is a tuple and we need to convert it to a 
dict
-                # This may need adjustment based on actual partition format
-                if isinstance(partition_value, tuple):
-                    # Create partition spec from partition tuple and table 
partition keys
-                    partition_spec = {}
-                    if len(partition_value) == len(self.table.partition_keys):
-                        for i, key in enumerate(self.table.partition_keys):
-                            partition_spec[key] = str(partition_value[i])
-                    else:
-                        # Fallback: use indices as keys
-                        for i, value in enumerate(partition_value):
-                            partition_spec[f"partition_{i}"] = str(value)
-                else:
-                    # If partition is already a dict or other format
-                    partition_spec = dict(partition_value) if partition_value 
else {}
-            else:
-                # Default partition for unpartitioned tables
-                partition_spec = {}
-
-            partition_key = tuple(sorted(partition_spec.items()))
+            partition_value = tuple(entry.partition.values)
+            if len(partition_value) != len(self.table.partition_keys):
+                raise ValueError('Partition row does not match the table 
partition keys')
+            # Java PartitionEntry.toPartitionStatistics reuses the path value
+            # computer, without path escaping. Group by typed partition values:
+            # NULL and whitespace remain distinct even if their names coincide.
+            partition_spec = dict(zip(self.table.partition_keys, 
path_factory._canonical_partition(partition_value)))
+            partition_key = tuple(bytes(value) if isinstance(value, 
(bytearray, memoryview)) else value
+                                  for value in partition_value)

Review Comment:
   [P2] Preserve BinaryRow identity when grouping partition statistics
   
   A tuple of ordinary Python values is not equivalent to the Java 
`Map<BinaryRow, PartitionEntry>` key. In particular `(0.0,) == (-0.0,)`, 
although these rows encode differently and name distinct `p=0.0`/`p=-0.0` 
partitions. With two records in each, this head publishes only `{'p': '0.0', 
record_count: 4}`; the base correctly produces two specs with count 2 each. 
Independently decoded identical NaNs have the opposite problem: Python NaNs 
compare unequal, so their statistics are not aggregated even when their 
BinaryRow bytes are identical. Both cases reproduce for FLOAT and DOUBLE. 
Please use a schema-aware binary partition identity, matching Java and Rust, 
rather than Python scalar equality; retain the intended distinction between 
NULL and whitespace.



-- 
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