xiangfu0 commented on code in PR #18870:
URL: https://github.com/apache/pinot/pull/18870#discussion_r3609468216


##########
pinot-core/src/main/java/org/apache/pinot/core/util/SegmentProcessorAvroUtils.java:
##########
@@ -24,20 +24,24 @@
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import org.apache.avro.Conversion;
+import org.apache.avro.LogicalType;
+import org.apache.avro.LogicalTypes;
 import org.apache.avro.Schema;
 import org.apache.avro.SchemaBuilder;
 import org.apache.avro.generic.GenericData;
-import 
org.apache.pinot.core.segment.processing.framework.SegmentProcessorFramework;
 import org.apache.pinot.spi.data.FieldSpec;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
 import org.apache.pinot.spi.data.readers.GenericRow;
 import org.apache.pinot.spi.ingestion.segment.writer.SegmentWriter;
+import org.apache.pinot.spi.utils.UuidUtils;
 
 
 /**
- * Helper methods for avro related conversions needed, when using AVRO as 
intermediate format in segment processing.
- * AVRO is used as intermediate processing format in {@link 
SegmentProcessorFramework} and file-based impl of
- * {@link SegmentWriter}
+ * Helper methods for Avro conversions used when serializing Pinot {@link 
GenericRow}s to Avro — by the file-based

Review Comment:
   Done — converted the class and the `convert*`/`Converts a Pinot schema` 
javadocs in this file to `///` markdown (the rest of the file was already 
markdown).
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-core/src/main/java/org/apache/pinot/core/util/SegmentProcessorAvroUtils.java:
##########
@@ -57,20 +61,85 @@ public static GenericData.Record 
convertGenericRowToAvroRecord(GenericRow generi
    */
   public static GenericData.Record convertGenericRowToAvroRecord(GenericRow 
genericRow,
       GenericData.Record reusableRecord, Set<String> fields) {
+    Schema avroSchema = reusableRecord.getSchema();
     for (String field : fields) {
       Object value = genericRow.getValue(field);
       if (value instanceof Object[]) {
+        // Array elements are written as-is. For MV UUID 
(array<string{logicalType:uuid}>) the elements are the raw
+        // 16-byte values; the uuid Conversion registered on the writer's data 
model (getAvroDataModel) renders each
+        // element to its canonical string at write time.
         reusableRecord.put(field, Arrays.asList((Object[]) value));
-      } else {
-        if (value instanceof byte[]) {
-          value = ByteBuffer.wrap((byte[]) value);
+      } else if (value instanceof byte[]) {
+        // A byte[] bound for a plain BYTES field must be wrapped as 
ByteBuffer (GenericDatumWriter requires it for the
+        // bytes type). A byte[] bound for a UUID field 
(string{logicalType:uuid}) is left raw so the uuid Conversion
+        // registered on the writer's data model (getAvroDataModel) renders it 
to a canonical string at write time.
+        Schema.Field avroField = avroSchema.getField(field);
+        if (avroField != null && avroField.schema().getType() == 
Schema.Type.BYTES) {

Review Comment:
   A `byte[]` value only ever originates from a BYTES or UUID column (both 
stored as 16-byte BYTES). The check keys off the Avro field type: BYTES fields 
need `ByteBuffer.wrap` (GenericDatumWriter requires it), while UUID fields 
(`string{logicalType:uuid}`) must stay raw `byte[]` so the registered 
`UuidConversion` renders them. No other type yields a `byte[]`, so the `else` 
branch is only ever UUID — it won't affect other types.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-plugins/pinot-input-format/pinot-avro-base/src/main/java/org/apache/pinot/plugin/inputformat/avro/AvroUtils.java:
##########
@@ -160,6 +161,16 @@ public static org.apache.avro.Schema 
getAvroSchemaFromPinotSchema(Schema pinotSc
     SchemaBuilder.FieldAssembler<org.apache.avro.Schema> fieldAssembler = 
SchemaBuilder.record("record").fields();
 
     for (FieldSpec fieldSpec : pinotSchema.getAllFieldSpecs()) {
+      if (fieldSpec.getDataType() == DataType.UUID) {

Review Comment:
   Not a bug. This path (`getAvroSchemaFromPinotSchema`) intentionally switches 
on the *stored* type because it serializes Pinot's physically-stored values 
(BOOLEAN→int, TIMESTAMP→long, etc.). UUID is special-cased so it keeps its 
logical Avro form (`string{logicalType:uuid}`) for round-trip fidelity instead 
of collapsing to bytes; switching the whole method to the original type would 
change BOOLEAN/TIMESTAMP output too, which is out of scope here.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-plugins/pinot-input-format/pinot-avro-base/src/main/java/org/apache/pinot/plugin/inputformat/avro/AvroUtils.java:
##########
@@ -323,16 +335,17 @@ private static void 
extractSchemaWithComplexTypeHandling(org.apache.avro.Schema
           extractSchemaWithComplexTypeHandling(elementType, fieldsToUnnest, 
delimiter, path, pinotSchema, fieldTypeMap,
               timeUnit, collectionNotUnnestedToJson);
         } else if (collectionNotUnnestedToJson == 
ComplexTypeConfig.CollectionNotUnnestedToJson.NON_PRIMITIVE
-            && AvroSchemaUtil.isPrimitiveType(elementType.getType())) {
-          addFieldToPinotSchema(pinotSchema, 
AvroSchemaUtil.valueOf(elementType.getType()), path, false, fieldTypeMap,
-              timeUnit);
+            && (AvroSchemaUtil.isPrimitiveType(elementType.getType())

Review Comment:
   `isPrimitiveType` returns true for 
INT/LONG/FLOAT/DOUBLE/BOOLEAN/STRING/ENUM, so STRING-backed UUID is already 
covered by it. The extra `|| valueOf(elementType) == UUID` clause only matters 
for FIXED(16)-backed UUID (raw Avro type FIXED, which is not primitive): it 
lets such array elements unnest as a UUID column instead of being dropped.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



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