/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.beam.sdk.transforms;
import com.google.common.collect.ImmutableMap;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import org.apache.beam.sdk.annotations.Internal;
import org.apache.beam.sdk.coders.CannotProvideCoderException;
import org.apache.beam.sdk.coders.Coder;
import org.apache.beam.sdk.coders.CoderRegistry;
import org.apache.beam.sdk.transforms.Combine.CombineFn;
import org.apache.beam.sdk.transforms.CombineWithContext.CombineFnWithContext;
import org.apache.beam.sdk.transforms.display.DisplayData;
import org.apache.beam.sdk.transforms.display.HasDisplayData;
import org.apache.beam.sdk.values.TypeDescriptor;
/**
* <b><i>For internal use only; no backwards-compatibility guarantees.</i></b>
*
* <p>This class contains the shared interfaces and abstract classes for different types of combine
* functions.
*
* <p>Users should not implement or extend them directly.
*/
@Internal
public class CombineFnBase {
/**
* <b><i>For internal use only; no backwards-compatibility guarantees.</i></b>
*
* <p>A {@code GloballyCombineFn<InputT, AccumT, OutputT>} specifies how to combine a
* collection of input values of type {@code InputT} into a single
* output value of type {@code OutputT}. It does this via one or more
* intermediate mutable accumulator values of type {@code AccumT}.
*
* <p>Do not implement this interface directly.
* Extends {@link CombineFn} and {@link CombineFnWithContext} instead.
*
* @param <InputT> type of input values
* @param <AccumT> type of mutable accumulator values
* @param <OutputT> type of output values
*/
@Internal
public interface GlobalCombineFn<InputT, AccumT, OutputT> extends Serializable, HasDisplayData {
/**
* Returns the {@code Coder} to use for accumulator {@code AccumT}
* values, or null if it is not able to be inferred.
*
* <p>By default, uses the knowledge of the {@code Coder} being used
* for {@code InputT} values and the enclosing {@code Pipeline}'s
* {@code CoderRegistry} to try to infer the Coder for {@code AccumT}
* values.
*
* <p>This is the Coder used to send data through a communication-intensive
* shuffle step, so a compact and efficient representation may have
* significant performance benefits.
*/
Coder<AccumT> getAccumulatorCoder(CoderRegistry registry, Coder<InputT> inputCoder)
throws CannotProvideCoderException;
/**
* Returns the {@code Coder} to use by default for output
* {@code OutputT} values, or null if it is not able to be inferred.
*
* <p>By default, uses the knowledge of the {@code Coder} being
* used for input {@code InputT} values and the enclosing
* {@code Pipeline}'s {@code CoderRegistry} to try to infer the
* Coder for {@code OutputT} values.
*/
Coder<OutputT> getDefaultOutputCoder(CoderRegistry registry, Coder<InputT> inputCoder)
throws CannotProvideCoderException;
/**
* Returns the error message for not supported default values in Combine.globally().
*/
String getIncompatibleGlobalWindowErrorMessage();
/**
* Returns the default value when there are no values added to the accumulator.
*/
OutputT defaultValue();
}
/**
* <b><i>For internal use only; no backwards-compatibility guarantees.</i></b>
*
* <p>An abstract {@link GlobalCombineFn} base class shared by {@link CombineFn} and {@link
* CombineFnWithContext}.
*
* <p>Do not extend this class directly. Extends {@link CombineFn} and {@link
* CombineFnWithContext} instead.
*
* @param <InputT> type of input values
* @param <AccumT> type of mutable accumulator values
* @param <OutputT> type of output values
*/
@Internal
abstract static class AbstractGlobalCombineFn<InputT, AccumT, OutputT>
implements GlobalCombineFn<InputT, AccumT, OutputT>, Serializable {
private static final String INCOMPATIBLE_GLOBAL_WINDOW_ERROR_MESSAGE =
"Default values are not supported in Combine.globally() if the output "
+ "PCollection is not windowed by GlobalWindows. Instead, use "
+ "Combine.globally().withoutDefaults() to output an empty PCollection if the input "
+ "PCollection is empty, or Combine.globally().asSingletonView() to get the default "
+ "output of the CombineFn if the input PCollection is empty.";
@Override
public Coder<AccumT> getAccumulatorCoder(CoderRegistry registry, Coder<InputT> inputCoder)
throws CannotProvideCoderException {
return registry.getCoder(getClass(), AbstractGlobalCombineFn.class,
ImmutableMap.<Type, Coder<?>>of(getInputTVariable(), inputCoder), getAccumTVariable());
}
@Override
public Coder<OutputT> getDefaultOutputCoder(CoderRegistry registry, Coder<InputT> inputCoder)
throws CannotProvideCoderException {
return registry.getCoder(getClass(), AbstractGlobalCombineFn.class,
ImmutableMap.<Type, Coder<?>>of(getInputTVariable(), inputCoder, getAccumTVariable(),
this.getAccumulatorCoder(registry, inputCoder)),
getOutputTVariable());
}
@Override
public String getIncompatibleGlobalWindowErrorMessage() {
return INCOMPATIBLE_GLOBAL_WINDOW_ERROR_MESSAGE;
}
/**
* Returns the {@link TypeVariable} of {@code InputT}.
*/
public TypeVariable<?> getInputTVariable() {
return (TypeVariable<?>)
new TypeDescriptor<InputT>(AbstractGlobalCombineFn.class) {}.getType();
}
/**
* Returns the {@link TypeVariable} of {@code AccumT}.
*/
public TypeVariable<?> getAccumTVariable() {
return (TypeVariable<?>)
new TypeDescriptor<AccumT>(AbstractGlobalCombineFn.class) {}.getType();
}
/**
* Returns the {@link TypeVariable} of {@code OutputT}.
*/
public TypeVariable<?> getOutputTVariable() {
return (TypeVariable<?>)
new TypeDescriptor<OutputT>(AbstractGlobalCombineFn.class) {}.getType();
}
/**
* {@inheritDoc}
*
* <p>By default, does not register any display data. Implementors may override this method
* to provide their own display data.
*/
@Override
public void populateDisplayData(DisplayData.Builder builder) {
}
}
}