Typed Streams в YTsaurus Flow (Java)

Java SDK Flow (Java и Kotlin) поддерживает типизированные стримы через FlowStreams.typed. Это позволяет автоматически сериализовать и десериализовать сообщения в POJO-объекты, что упрощает работу с данными в ProcessFunction.

Бинарный формат нетипизированных (FlowStreams.raw) и типизированных (FlowStreams.typed) стримов полностью идентичен и соответствует бинарному формату UnversionedRow в varint энкодинге, используемому во Flow для передачи данных между узлами кластера.

Entity

POJO-классы для стримов описываются с помощью JPA-аннотаций @Entity и @Column. При этом класс должен иметь конструктор по умолчанию.

@Entity
public class Hit {
    @Column(name = "hit_id")
    private String hitId;

    @Column(name = "hit_time", columnDefinition = "uint64")
    private Long hitTime;

    @Column(name = "hit_payload")
    private String hitPayload;

    // конструкторы, геттеры, сеттеры...
}
@Entity
class Hit {
    @Column(name = "hit_id")
    var hitId: String? = null

    @Column(name = "hit_time", columnDefinition = "uint64")
    var hitTime: Long? = null

    @Column(name = "hit_payload")
    var hitPayload: String? = null

    // конструкторы, геттеры, сеттеры...
}

Важно

Порядок полей в типизированной модели данных должен совпадать с порядком колонок в определении стрима в статической спеке. Нарушение порядка полей может приводить к сложнодиагностируемым ошибкам.

Если стрим в спеке не описан, порядок колонок задаёт сама модель — тогда следить нужно за совместимостью с очередями и таблицами, в которые пишет пайплайн.

Если стримы зарегистрированы через FlowStreams.raw, сообщения будут доступны в нетипизированном виде. Получить значение полей из нетипизированного сообщения можно через message.get("field_name", Type.class).

Подробнее о работе с типизированными и нетипизированными сообщениями см. Process Function.

Column

Аннотация @Column является необязательной. Если на поле класса нет аннотации, то в качестве имени колонки будет использоваться имя поля.

@Column позволяет задать имя колонки через атрибут name, а также указать тип колонки через атрибут columnDefinition.

Атрибут columnDefinition принимает строку с именем Type V3. Полный список типов.

Регистрация стримов

Все типизированные стримы необходимо зарегистрировать до старта companion-сервера.

Через аннотацию @FlowMessage (рекомендуется)

POJO-класс сообщения помечается аннотацией @FlowMessage со списком идентификаторов стримов (streamIds), которые он обслуживает. Аннотация используется вместе с @Entity (из которой выводится схема) и не заменяет её. Один POJO может обслуживать несколько стримов с одинаковой схемой — в этом случае в streamIds указывается несколько идентификаторов.

@Entity
@FlowMessage(streamIds = {"hit"})
public class Hit {
    // поля...
}
@Entity
@FlowMessage(streamIds = ["hit"])
class Hit {
    // поля...
}

В Spring Boot-приложениях такие классы находятся сканированием пакетов приложения и регистрируются автоматически. По умолчанию сканируются пакеты автоконфигурации Spring Boot (пакет класса с @SpringBootApplication и вложенные пакеты). Дополнительные пакеты можно указать свойством flow.entity-scan-packages.

Без Spring Boot классы передаются напрямую в PipelineContext.registerTypedStreams:

context.registerTypedStreams(Hit.class, Action.class, JoinedAction.class);
context.registerTypedStreams(Hit::class.java, Action::class.java, JoinedAction::class.java)

Через FlowStreams.typed (императивно)

Типизированные стримы также можно создать и зарегистрировать вручную через фабричный метод FlowStreams.typed, который принимает два аргумента: streamId и класс сообщения. В Spring Boot-приложениях стримы можно объявить через ComputationProvider (метод getStreams()) либо как отдельные бины FlowStream<?>.

context.registerStream(FlowStreams.typed("hit", Hit.class));
context.registerStream(FlowStreams.typed("action", Action.class));
context.registerStream(FlowStreams.typed("joined_action", JoinedAction.class));
context.registerStream(FlowStreams.typed("hit", Hit::class.java))
context.registerStream(FlowStreams.typed("action", Action::class.java))
context.registerStream(FlowStreams.typed("joined_action", JoinedAction::class.java))
Предыдущая