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


##########
pinot-core/src/main/java/org/apache/pinot/core/util/SegmentProcessorAvroUtils.java:
##########
@@ -57,20 +61,50 @@ 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[]) {
-        reusableRecord.put(field, Arrays.asList((Object[]) value));
+        Schema.Field avroField = avroSchema.getField(field);
+        if (avroField != null && isUuidArrayLogicalType(avroField.schema())) {
+          // MV UUID columns are emitted with an Avro 
array<string{logicalType:uuid}> schema; convert each
+          // 16-byte element to its canonical UUID string so 
GenericDatumWriter accepts the record.

Review Comment:
   Good suggestion — registering an Avro `Conversion` on the writer's 
`GenericData` would be cleaner than the manual `byte[]` → canonical-string 
rendering. Tracking this as a follow-up rather than expanding this PR's scope.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-core/src/main/java/org/apache/pinot/core/segment/processing/genericrow/GenericRowDeserializer.java:
##########
@@ -164,6 +164,16 @@ public void deserialize(long offset, GenericRow buffer) {
               multiValue[j] = new String(stringBytes, UTF_8);
             }
             break;
+          case BYTES:

Review Comment:
   MV `BYTES` (de)serialization is required by MV `UUID` here, since UUID's 
stored type is `BYTES` — so that part stays in this PR. The MV `BIG_DECIMAL` 
gap is genuinely separable and will be handled in a follow-up bugfix.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/indexsegment/mutable/MutableSegmentImpl.java:
##########
@@ -753,16 +747,39 @@ private DedupRecordInfo getDedupRecordInfo(GenericRow 
row) {
   }
 
   private RecordInfo getRecordInfo(GenericRow row, int docId) {
-    PrimaryKey primaryKey = row.getPrimaryKey(_schema.getPrimaryKeyColumns());
+    PrimaryKey primaryKey = getPrimaryKey(row);
     Comparable comparisonValue = getComparisonValue(row);
     boolean deleteRecord = _deleteRecordColumn != null && 
BooleanUtils.toBoolean(row.getValue(_deleteRecordColumn));
     return new RecordInfo(primaryKey, docId, comparisonValue, deleteRecord);
   }
 
+  private PrimaryKey getPrimaryKey(GenericRow row) {
+    List<String> primaryKeyColumns = _schema.getPrimaryKeyColumns();
+    int numPrimaryKeyColumns = primaryKeyColumns.size();
+    Object[] values = new Object[numPrimaryKeyColumns];
+    for (int i = 0; i < numPrimaryKeyColumns; i++) {
+      String primaryKeyColumn = primaryKeyColumns.get(i);
+      Object value = row.getValue(primaryKeyColumn);
+      DataType dataType = 
_schema.getFieldSpecFor(primaryKeyColumn).getDataType();
+      values[i] = normalizePrimaryKeyValue(value, dataType, primaryKeyColumn);
+    }
+    return new PrimaryKey(values);
+  }
+
+  private Object normalizePrimaryKeyValue(@Nullable Object value, DataType 
dataType, String column) {

Review Comment:
   You're right — it is redundant. After #18927 the record transformer already 
yields `byte[]` for UUID columns, and `GenericRow.getPrimaryKey` wraps `byte[]` 
into `ByteArray`, so the schema-aware normalization adds nothing. Tracking 
removal (reverting to `row.getPrimaryKey(_schema.getPrimaryKeyColumns())`) as a 
follow-up.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/creator/BloomFilterCreator.java:
##########
@@ -33,6 +34,8 @@ public interface BloomFilterCreator extends IndexCreator {
   default void add(Object value, int dictId) {
     if (getDataType() == FieldSpec.DataType.BYTES) {
       add(BytesUtils.toHexString((byte[]) value));
+    } else if (getDataType() == FieldSpec.DataType.UUID) {

Review Comment:
   Yes — the value reaching `add()` is already the canonical 16-byte form. 
Storing the hex (storage) format would work, but it has to change together with 
the query side: `ValueBasedSegmentPruner` currently probes the bloom filter 
with the same canonical-string rendering, so switching only the creator would 
make every UUID probe miss. Keeping both on the canonical string for now; 
tracking the hex alignment as a follow-up.
   
   _🤖 Addressed by [Claude Code](https://claude.com/claude-code)_



##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/loader/columnminmaxvalue/ColumnMinMaxValueGenerator.java:
##########
@@ -360,26 +360,28 @@ private void 
addColumnMinMaxValueWithoutDictionary(ColumnMetadata columnMetadata
           break;
         }
         case BYTES: {
+          // ByteArray.compare is unsigned byte-wise lexicographic; for 
canonical 16-byte big-endian UUIDs this is
+          // identical to UuidUtils.compare's unsigned 64-bit-word ordering, 
so a single comparator is sufficient.
           byte[] min = null;
           byte[] max = null;
           if (isSingleValue) {
             for (int docId = 0; docId < numDocs; docId++) {
               byte[] value = rawIndexReader.getBytes(docId, readerContext);
-              if (min == null || ByteArray.compare(value, min) > 0) {
+              if (min == null || ByteArray.compare(value, min) < 0) {

Review Comment:
   Agreed — the raw no-dictionary BYTES min/max comparisons were inverted (min 
stored as max and vice versa). It's a real bug but orthogonal to UUID support, 
so it will be extracted into its own PR.
   
   _🤖 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