Skip to content

Commit a15b880

Browse files
authored
Merge pull request #39043: Improve WithKeys coder inference context
1 parent abe3fc7 commit a15b880

2 files changed

Lines changed: 42 additions & 13 deletions

File tree

sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/WithKeys.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,27 +110,33 @@ public WithKeys<K, V> withKeyType(TypeDescriptor<K> keyType) {
110110

111111
@Override
112112
public PCollection<KV<K, V>> expand(PCollection<V> in) {
113+
SerializableFunction<V, K> localFn = fn;
114+
TypeDescriptor<V> inputType = in.getTypeDescriptor();
115+
TypeDescriptor<KV<K, V>> outputType = getOutputTypeDescriptor(inputType);
113116
PCollection<KV<K, V>> result =
114117
in.apply(
115118
"AddKeys",
116-
MapElements.via(
117-
new SimpleFunction<V, KV<K, V>>() {
118-
@Override
119-
public KV<K, V> apply(V element) {
120-
return KV.of(fn.apply(element), element);
121-
}
122-
}));
119+
outputType == null
120+
? MapElements.via(
121+
new SimpleFunction<V, KV<K, V>>() {
122+
@Override
123+
public KV<K, V> apply(V element) {
124+
return KV.of(localFn.apply(element), element);
125+
}
126+
})
127+
: MapElements.into(outputType)
128+
.via(
129+
(SerializableFunction<V, KV<K, V>>)
130+
element -> KV.of(localFn.apply(element), element)));
123131

124132
try {
125-
Coder<K> keyCoder;
126133
CoderRegistry coderRegistry = in.getPipeline().getCoderRegistry();
127-
if (keyType == null) {
128-
keyCoder = coderRegistry.getOutputCoder(fn, in.getCoder());
134+
if (outputType == null) {
135+
Coder<K> keyCoder = coderRegistry.getOutputCoder(fn, in.getCoder());
136+
result.setCoder(KvCoder.of(keyCoder, in.getCoder()));
129137
} else {
130-
keyCoder = coderRegistry.getCoder(keyType);
138+
result.setCoder(coderRegistry.getCoder(outputType, checkNotNull(inputType), in.getCoder()));
131139
}
132-
// TODO: Remove when we can set the coder inference context.
133-
result.setCoder(KvCoder.of(keyCoder, in.getCoder()));
134140
} catch (CannotProvideCoderException exc) {
135141
if (keyType != null) {
136142
try {
@@ -151,4 +157,12 @@ public KV<K, V> apply(V element) {
151157

152158
return result;
153159
}
160+
161+
private @Nullable TypeDescriptor<KV<K, V>> getOutputTypeDescriptor(
162+
@Nullable TypeDescriptor<V> inputType) {
163+
if (keyType == null || inputType == null) {
164+
return null;
165+
}
166+
return TypeDescriptors.kvs(keyType, inputType);
167+
}
154168
}

sdks/java/core/src/test/java/org/apache/beam/sdk/transforms/WithKeysTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,21 @@ public void withLambdaAndParameterizedTypeDescriptorShouldSucceed() {
172172
p.run();
173173
}
174174

175+
@Test
176+
public void withKeyTypeShouldSetOutputTypeDescriptorFromInputType() {
177+
PCollection<String> values =
178+
p.apply(Create.of("1234", "3210").withType(TypeDescriptors.strings()));
179+
180+
PCollection<KV<Integer, String>> kvs =
181+
values.apply(
182+
WithKeys.of((SerializableFunction<String, Integer>) Integer::valueOf)
183+
.withKeyType(TypeDescriptors.integers()));
184+
185+
assertEquals(
186+
TypeDescriptors.kvs(TypeDescriptors.integers(), TypeDescriptors.strings()),
187+
kvs.getTypeDescriptor());
188+
}
189+
175190
@Test
176191
@Category(NeedsRunner.class)
177192
public void withLambdaAndNoTypeDescriptorShouldThrow() {

0 commit comments

Comments
 (0)