asif-moh commented on code in PR #3607:
URL: https://github.com/apache/parquet-java/pull/3607#discussion_r3400521468


##########
parquet-hadoop/src/main/java/org/apache/parquet/format/converter/ParquetMetadataConverter.java:
##########
@@ -970,6 +970,46 @@ public org.apache.parquet.column.statistics.Statistics 
fromParquetStatistics(
     return fromParquetStatisticsInternal(createdBy, statistics, type, 
expectedOrder);
   }
 
+  // Overload that uses a pre-computed shouldIgnoreCorruptStats flag to avoid 
redundant parsing
+  private org.apache.parquet.column.statistics.Statistics 
fromParquetStatisticsInternal(
+      String createdBy, Statistics formatStats, PrimitiveType type, boolean 
shouldIgnoreCorruptStats) {
+    SortOrder typeSortOrder = overrideSortOrderToSigned(type) ? 
SortOrder.SIGNED : sortOrder(type);
+    org.apache.parquet.column.statistics.Statistics.Builder statsBuilder =
+        
org.apache.parquet.column.statistics.Statistics.getBuilderForReading(type);
+
+    if (formatStats != null) {
+      if (formatStats.isSetMin_value() && formatStats.isSetMax_value()) {
+        byte[] min = formatStats.min_value.array();
+        byte[] max = formatStats.max_value.array();
+        if (isMinMaxStatsSupported(type) || Arrays.equals(min, max)) {
+          statsBuilder.withMin(min);
+          statsBuilder.withMax(max);
+        }
+      } else {
+        boolean isSet = formatStats.isSetMax() && formatStats.isSetMin();
+        boolean maxEqualsMin = isSet ? Arrays.equals(formatStats.getMin(), 
formatStats.getMax()) : false;
+        boolean sortOrdersMatch = SortOrder.SIGNED == typeSortOrder;
+        // The shouldIgnoreCorruptStats flag applies only to BINARY and 
FIXED_LEN_BYTE_ARRAY.
+        // For other types, shouldIgnoreStatistics always returns false, so we 
only guard those.
+        PrimitiveTypeName primitiveTypeName = type.getPrimitiveTypeName();
+        boolean ignoreForThisColumn = shouldIgnoreCorruptStats
+            && (primitiveTypeName == PrimitiveTypeName.BINARY
+                || primitiveTypeName == 
PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY);
+        if (!ignoreForThisColumn && (sortOrdersMatch || maxEqualsMin)) {

Review Comment:
   This check in `shouldIgnoreStatistics` is dead code with current changes as 
we always pass `BINARY`
   ```
   if (columnType != PrimitiveTypeName.BINARY && columnType 
!=PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY)
   ```
   We can utilize the new methods here. Please refer to below comments for 
context. 
   
   ```
   if (!(fileHasCorruptStats && 
CorruptStatistics.isCorruptStatisticsColumnType(type.getPrimitiveTypeName()))
   ```
   
   Instead of calling or moving the `PrimitiveTypeName` checks to 
`ParquetMetadataConverter` and leave it as the responsibility of 
`CorruptStatistics`
   ```
   if (!CorruptStatistics.shouldIgnoreStatistics(createdBy, 
type.getPrimitiveTypeName())
   ```



##########
parquet-hadoop/src/main/java/org/apache/parquet/format/converter/ParquetMetadataConverter.java:
##########
@@ -1829,6 +1880,10 @@ public ParquetMetadata fromParquetMetadata(
     MessageType messageType = fromParquetSchema(parquetMetadata.getSchema(), 
parquetMetadata.getColumn_orders());
     List<BlockMetaData> blocks = new ArrayList<BlockMetaData>();
     List<RowGroup> row_groups = parquetMetadata.getRow_groups();
+    // Compute once per file: the result is the same for BINARY and 
FIXED_LEN_BYTE_ARRAY
+    // (the only types affected by PARQUET-251), and always false for other 
types.
+    boolean shouldIgnoreCorruptStats =
+        
CorruptStatistics.shouldIgnoreStatistics(parquetMetadata.getCreated_by(), 
PrimitiveTypeName.BINARY);

Review Comment:
   This is calling `shouldIgnoreStatistics` with `PrimitiveTypeName.BINARY` 
hardcoded which is incorrect.
   
   Instead we can refactor `shouldIgnoreStatistics` by adding public methods. 
   ```
   public static boolean shouldIgnoreStatistics(String createdBy, 
PrimitiveTypeName columnType) {
       if (!isCorruptStatisticsColumnType(columnType)) {
         // the bug only applies to binary columns
         return false;
       }
       return fileHasCorruptStatistics(createdBy);
   }
   
   public static boolean isCorruptStatisticsColumnType(PrimitiveTypeName 
columnType) {
       return columnType == PrimitiveTypeName.BINARY || columnType == 
PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY;
   }
   
   public static boolean fileHasCorruptStatistics(String createdBy) {
       // rest of the logic from shouldIgnoreStatistics
   }
   ```



##########
parquet-hadoop/src/main/java/org/apache/parquet/format/converter/ParquetMetadataConverter.java:
##########
@@ -970,6 +970,46 @@ public org.apache.parquet.column.statistics.Statistics 
fromParquetStatistics(
     return fromParquetStatisticsInternal(createdBy, statistics, type, 
expectedOrder);
   }
 
+  // Overload that uses a pre-computed shouldIgnoreCorruptStats flag to avoid 
redundant parsing
+  private org.apache.parquet.column.statistics.Statistics 
fromParquetStatisticsInternal(

Review Comment:
   Instead of duplicating the entire `fromParquetStatisticsInternal` body, the 
existing method can simply delegate to a new overload and this eliminates 
duplicate code
   
   ```
   static org.apache.parquet.column.statistics.Statistics 
fromParquetStatisticsInternal(
         String createdBy, Statistics formatStats, PrimitiveType type, 
SortOrder typeSortOrder) {
       return fromParquetStatisticsInternal(
           formatStats, 
           type, 
           typeSortOrder, 
           CorruptStatistics.fileHasCorruptStatistics(createdBy) // This is a 
new method in CorruptStatistics
       );
   }
   
   
   // overloaded method
   static org.apache.parquet.column.statistics.Statistics 
fromParquetStatisticsInternal(
         Statistics formatStats, PrimitiveType type, SortOrder typeSortOrder, 
boolean fileHasCorruptStats) {
   ```



##########
parquet-hadoop/src/main/java/org/apache/parquet/format/converter/ParquetMetadataConverter.java:
##########
@@ -1794,13 +1834,24 @@ public FileMetaDataAndRowGroupOffsetInfo 
visit(RangeMetadataFilter filter) throw
 
   public ColumnChunkMetaData buildColumnChunkMetaData(
       ColumnMetaData metaData, ColumnPath columnPath, PrimitiveType type, 
String createdBy) {
+    boolean shouldIgnoreCorruptStats =
+        CorruptStatistics.shouldIgnoreStatistics(createdBy, 
PrimitiveTypeName.BINARY);
+    return buildColumnChunkMetaData(metaData, columnPath, type, createdBy, 
shouldIgnoreCorruptStats);
+  }
+
+  ColumnChunkMetaData buildColumnChunkMetaData(

Review Comment:
    `buildColumnChunkMetaData` can delegate to a package-private overload that 
takes the boolean similar to what you have done but with few changes,
   ```
   public ColumnChunkMetaData buildColumnChunkMetaData(
         ColumnMetaData metaData, ColumnPath columnPath, PrimitiveType type, 
String createdBy) {
       return buildColumnChunkMetaData(
           metaData, columnPath, type, 
CorruptStatistics.fileHasCorruptStatistics(createdBy));
   }
   
   ColumnChunkMetaData buildColumnChunkMetaData(
         ColumnMetaData metaData, ColumnPath columnPath, PrimitiveType type, 
boolean fileHasCorruptStats) {
       SortOrder expectedOrder = overrideSortOrderToSigned(type) ? 
SortOrder.SIGNED : sortOrder(type);
       return ColumnChunkMetaData.get(...,
           fromParquetStatisticsInternal(metaData.statistics, type, 
expectedOrder, fileHasCorruptStats), ...);
   }
   ```
   No need to pass createdBy downstream, the boolean is all the internal 
overload needs. SortOrder computation moves here since we bypass 
`fromParquetStatistics` to avoid re-parsing createdBy as you have already done 
by replacing `fromParquetStatisticsInternal` with `fromParquetStatistics`.
   
   Also notice how the new public methods we extracted in `CorruptStatistics` 
are being used in each delegate method here



##########
parquet-hadoop/src/main/java/org/apache/parquet/format/converter/ParquetMetadataConverter.java:
##########


Review Comment:
   We no longer need to pass `createdBy` downstream



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


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to