Static Table Join in YTsaurus Flow (Java and Kotlin)
This pipeline loads a static reference table into external state and enriches queue events by the shared key. Java and Kotlin use the same SDK and pipeline topology.
Pipeline structure
reference_readerreads the static reference table;reference_loadernormalizes each reference value and writes it to/reference_statethroughexternal_state_managers;event_readerreads events from a queue;enricherreads/reference_statethroughexternal_state_joinersand publishes only successful matches toenriched.
The manager and joiner point to the same dynamic state table. Their keys must match the group_by_schema of their computations. See the Java pipeline spec or Kotlin pipeline spec.
Load the reference state
Java
Kotlin
@Override
public void onMessage(ExtendedMessage message, OutputCollector output, RuntimeContext ctx) {
String name = message.get("name", String.class);
String normalizedName = name.strip().toLowerCase();
ExternalStateAccessor stateAccessor = ctx.getState(REFERENCE_STATE, message);
stateAccessor.set(stateAccessor.getOrDefault().toBuilder()
.set("normalized_name", normalizedName)
.finish());
}
override fun onMessage(message: ExtendedMessage, output: OutputCollector, ctx: RuntimeContext) {
val normalizedName = message.get("name", String::class.java)?.trim()?.lowercase() ?: return
val stateAccessor = ctx.getState(REFERENCE_STATE, message)
stateAccessor.set(
stateAccessor.orDefault.toBuilder()
.set("normalized_name", normalizedName)
.finish()
)
}
Enrich events
The read-only descriptor selects the joined row by the current message key. If the row or normalized_name is absent, the example produces no output.
Java
Kotlin
@Override
public void onMessage(ExtendedMessage message, OutputCollector output, RuntimeContext ctx) {
ReadOnlyExternalStateAccessor stateAccessor = ctx.getState(REFERENCE_STATE, message);
String normalizedName = stateAccessor.getOrDefault().get("normalized_name", String.class);
if (normalizedName == null) {
return;
}
output.addMessage(ctx.createMessageBuilder("enriched")
.set("key", message.get("key", Long.class))
.set("name", normalizedName)
.finish());
}
override fun onMessage(message: ExtendedMessage, output: OutputCollector, ctx: RuntimeContext) {
val stateAccessor = ctx.getState(REFERENCE_STATE, message)
val normalizedName = stateAccessor.orDefault.get("normalized_name", String::class.java) ?: return
output.addMessage(
ctx.createMessageBuilder("enriched")
.set("key", message.get("key", Long::class.java))
.set("name", normalizedName)
.finish()
)
}
Both computations are discovered through @FlowComputation; the pipeline spec declares the three stream schemas used by the native sources and companion functions.
See also
Previous