Skip to content

Commit bcfa987

Browse files
committed
feat: add reorderable record and reorderable struct
1 parent 9a0a578 commit bcfa987

File tree

5 files changed

+400
-0
lines changed

5 files changed

+400
-0
lines changed

odps-sdk/odps-sdk-commons/src/main/java/com/aliyun/odps/data/SimpleStruct.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ public Object getFieldValue(String fieldName) {
7575
return null;
7676
}
7777

78+
@Override
79+
public TypeInfo getTypeInfo() {
80+
return typeInfo;
81+
}
82+
7883
@Override
7984
public List<Object> getFieldValues() {
8085
return values;

odps-sdk/odps-sdk-commons/src/main/java/com/aliyun/odps/data/Struct.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public interface Struct extends Serializable {
1717
Object getFieldValue(int index);
1818
TypeInfo getFieldTypeInfo(String fieldName);
1919
Object getFieldValue(String fieldName);
20+
TypeInfo getTypeInfo();
2021
List<Object> getFieldValues();
2122
@Override
2223
String toString();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.aliyun.odps.data;
2+
3+
import com.aliyun.odps.Column;
4+
import com.aliyun.odps.TableSchema;
5+
import com.aliyun.odps.type.NestedTypeInfo;
6+
import com.aliyun.odps.type.TypeInfo;
7+
8+
/**
9+
* @author dingxin ([email protected])
10+
*/
11+
public class ReorderableRecord extends ArrayRecord {
12+
13+
@Override
14+
public void set(int idx, Object value) {
15+
TypeInfo typeInfo = getColumns()[idx].getTypeInfo();
16+
if (typeInfo instanceof NestedTypeInfo) {
17+
value = ReorderableStruct.reorderNestedType(value, null, typeInfo);
18+
}
19+
super.set(idx, value);
20+
}
21+
22+
public ReorderableRecord(Column[] columns) {
23+
super(columns);
24+
}
25+
26+
public ReorderableRecord(Column[] columns, boolean strictTypeValidation) {
27+
super(columns, strictTypeValidation);
28+
}
29+
30+
public ReorderableRecord(Column[] columns, boolean strictTypeValidation, Long fieldMaxSize) {
31+
super(columns, strictTypeValidation, fieldMaxSize);
32+
}
33+
34+
public ReorderableRecord(Column[] columns, Object[] values) {
35+
super(columns, values);
36+
}
37+
38+
public ReorderableRecord(Column[] columns, Object[] values, boolean strictTypeValidation) {
39+
super(columns, values, strictTypeValidation);
40+
}
41+
42+
public ReorderableRecord(TableSchema schema) {
43+
super(schema);
44+
}
45+
46+
public ReorderableRecord(TableSchema schema, boolean strictTypeValidation) {
47+
super(schema, strictTypeValidation);
48+
}
49+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package com.aliyun.odps.data;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import com.aliyun.odps.type.ArrayTypeInfo;
9+
import com.aliyun.odps.type.MapTypeInfo;
10+
import com.aliyun.odps.type.NestedTypeInfo;
11+
import com.aliyun.odps.type.StructTypeInfo;
12+
import com.aliyun.odps.type.TypeInfo;
13+
14+
/**
15+
* @author dingxin ([email protected])
16+
*/
17+
public class ReorderableStruct extends SimpleStruct {
18+
19+
/**
20+
* lower field name to index
21+
*/
22+
private Map<String, Integer> fieldNameToIndex;
23+
24+
/**
25+
* A implements of {@link Struct}, which can reorder values into mc table order
26+
*
27+
* @param type type of the struct
28+
* @param values values of the struct
29+
* be careful: the struct value list is a reference of this param
30+
*/
31+
public ReorderableStruct(StructTypeInfo type, List<Object> values) {
32+
super(type, values);
33+
rebuildFieldNameIndexMap();
34+
}
35+
36+
private void rebuildFieldNameIndexMap() {
37+
fieldNameToIndex = new HashMap<>();
38+
List<String> fieldNames = typeInfo.getFieldNames();
39+
for (int index = 0; index < typeInfo.getFieldCount(); index++) {
40+
fieldNameToIndex.put(fieldNames.get(index).toLowerCase(), index);
41+
}
42+
}
43+
44+
public void set(String fieldName, Object value) {
45+
values.set(fieldNameToIndex.get(fieldName.toLowerCase()), value);
46+
}
47+
48+
public Object get(String fieldName) {
49+
return getFieldValue(fieldNameToIndex.get(fieldName.toLowerCase()));
50+
}
51+
52+
public synchronized void reorder(StructTypeInfo orderedType) {
53+
List<String> orderedTypeFieldNames = orderedType.getFieldNames();
54+
if (orderedTypeFieldNames.size() != typeInfo.getFieldNames().size()) {
55+
throw new IllegalArgumentException("The orderedType is not compatible with this struct");
56+
}
57+
58+
List<Object> newValues = new ArrayList<>();
59+
List<TypeInfo> newTypeInfos = orderedType.getFieldTypeInfos();
60+
61+
for (int index = 0; index < orderedType.getFieldCount(); index++) {
62+
String colName = orderedTypeFieldNames.get(index).toLowerCase();
63+
Integer oldIndex = fieldNameToIndex.get(colName);
64+
if (oldIndex == null) {
65+
throw new IllegalArgumentException("Field " + colName + " not found in original struct");
66+
}
67+
Object oldValue = values.get(oldIndex);
68+
TypeInfo oldTypeInfo = typeInfo.getFieldTypeInfos().get(oldIndex);
69+
TypeInfo newTypeInfo = newTypeInfos.get(index);
70+
71+
// Handle nested types
72+
if (oldTypeInfo instanceof NestedTypeInfo) {
73+
Object reorderedValue = reorderNestedType(oldValue, oldTypeInfo, newTypeInfo);
74+
newValues.add(reorderedValue);
75+
} else {
76+
newValues.add(oldValue);
77+
}
78+
}
79+
// update internal state
80+
this.values = newValues;
81+
this.typeInfo = orderedType;
82+
rebuildFieldNameIndexMap();
83+
}
84+
85+
public static Object reorderNestedType(Object value, TypeInfo oldTypeInfo, TypeInfo newTypeInfo) {
86+
if (oldTypeInfo != null && oldTypeInfo.getOdpsType() != newTypeInfo.getOdpsType()) {
87+
throw new IllegalArgumentException("The nested type is not compatible");
88+
}
89+
if (newTypeInfo instanceof StructTypeInfo) {
90+
if (oldTypeInfo == null) {
91+
oldTypeInfo = ((Struct) value).getTypeInfo();
92+
}
93+
// Automatically wrap ordinary Struct as ReorderableStruct
94+
if (!(value instanceof ReorderableStruct)) {
95+
value = new ReorderableStruct((StructTypeInfo) oldTypeInfo, ((Struct) value).getFieldValues());
96+
}
97+
// Recursively process nested structures
98+
ReorderableStruct struct = (ReorderableStruct) value;
99+
struct.reorder((StructTypeInfo) newTypeInfo);
100+
return struct;
101+
} else if (newTypeInfo instanceof ArrayTypeInfo) {
102+
ArrayTypeInfo newArrayTypeInfo = (ArrayTypeInfo) newTypeInfo;
103+
TypeInfo newElementTypeInfo = newArrayTypeInfo.getElementTypeInfo();
104+
105+
if (newElementTypeInfo instanceof NestedTypeInfo) {
106+
// Recursively process nested structures
107+
List<?> originalList = (List<?>) value;
108+
List<Object> newList = new ArrayList<>();
109+
for (Object element : originalList) {
110+
newList.add(reorderNestedType(element, null, newElementTypeInfo));
111+
}
112+
return newList;
113+
}
114+
} else if (newTypeInfo instanceof MapTypeInfo) {
115+
MapTypeInfo newMapTypeInfo = (MapTypeInfo) newTypeInfo;
116+
TypeInfo newKeyTypeInfo = newMapTypeInfo.getKeyTypeInfo();
117+
TypeInfo newValueTypeInfo = newMapTypeInfo.getValueTypeInfo();
118+
119+
if (newKeyTypeInfo instanceof NestedTypeInfo
120+
|| newValueTypeInfo instanceof NestedTypeInfo) {
121+
// Recursively process nested structures
122+
Map<?, ?> originalMap = (Map<?, ?>) value;
123+
Map<Object, Object> newMap = new HashMap<>();
124+
for (Map.Entry<?, ?> entry : originalMap.entrySet()) {
125+
Object reorderedKey = entry.getKey();
126+
if (newKeyTypeInfo instanceof NestedTypeInfo) {
127+
reorderedKey =
128+
reorderNestedType(entry.getKey(), null, newKeyTypeInfo);
129+
}
130+
Object reorderedValue = entry.getValue();
131+
132+
if (newValueTypeInfo instanceof NestedTypeInfo) {
133+
reorderedValue =
134+
reorderNestedType(entry.getValue(), null, newValueTypeInfo);
135+
}
136+
newMap.put(reorderedKey, reorderedValue);
137+
}
138+
return newMap;
139+
}
140+
}
141+
// The basic type or type that does not require reordering will return directly to the original value
142+
return value;
143+
}
144+
}

0 commit comments

Comments
 (0)