Implementation:Apache Paimon RowKind Python
| Knowledge Sources | |
|---|---|
| Domains | Changelog Semantics, Row Representation |
| Last Updated | 2026-02-08 00:00 GMT |
Overview
RowKind is an enumeration representing the type of change that a row describes in a changelog: insert, update, or delete.
Description
The RowKind enum defines four change types used in Apache Paimon's changelog semantics: INSERT (+I), UPDATE_BEFORE (-U), UPDATE_AFTER (+U), and DELETE (-D). These types enable tracking of row changes in streaming and batch processing scenarios.
The enum provides utility methods to check if a RowKind represents an addition (INSERT or UPDATE_AFTER), convert to string representation (e.g., "+I"), and parse from string format. It also includes a static byte-level check method that avoids object creation for performance optimization.
RowKind is fundamental to Paimon's merge-on-read architecture, where different row kinds determine how records are merged during compaction and reading. INSERT and UPDATE_AFTER are considered additions that should be retained, while DELETE and UPDATE_BEFORE mark records for removal or replacement.
Usage
Use RowKind when implementing changelog processing, merge logic, CDC (Change Data Capture) integration, or any operation that needs to distinguish between different types of row changes.
Code Reference
Source Location
- Repository: Apache_Paimon
- File: paimon-python/pypaimon/table/row/row_kind.py
Signature
class RowKind(Enum):
"""Row change kind enumeration."""
INSERT = 0 # +I: Insertion operation
UPDATE_BEFORE = 1 # -U: Update operation with previous content
UPDATE_AFTER = 2 # +U: Update operation with new content
DELETE = 3 # -D: Deletion operation
def is_add(self) -> bool:
"""Check if this RowKind is an addition (INSERT or UPDATE_AFTER)."""
def to_string(self) -> str:
"""Convert to string representation (+I, -U, +U, -D)."""
@staticmethod
def from_string(kind_str: str) -> 'RowKind':
"""Parse RowKind from string."""
@classmethod
def is_add_byte(cls, byte: int) -> bool:
"""Check if byte value represents an add operation (0 or 2)."""
Import
from pypaimon.table.row.row_kind import RowKind
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| kind_str | str | Yes (for from_string) | String representation (+I, -U, +U, -D) |
| byte | int | Yes (for is_add_byte) | Byte value (0, 1, 2, or 3) |
Outputs
| Name | Type | Description |
|---|---|---|
| row_kind | RowKind | RowKind enum value |
| is_add | bool | True if INSERT or UPDATE_AFTER |
| kind_string | str | String representation of RowKind |
Usage Examples
from pypaimon.table.row.row_kind import RowKind
# Create RowKind values
insert = RowKind.INSERT
update_before = RowKind.UPDATE_BEFORE
update_after = RowKind.UPDATE_AFTER
delete = RowKind.DELETE
# Check if addition
if insert.is_add():
print("This is an addition") # True
if update_after.is_add():
print("This is an addition") # True
if delete.is_add():
print("This is an addition") # False
# Convert to string
print(insert.to_string()) # "+I"
print(update_before.to_string()) # "-U"
print(update_after.to_string()) # "+U"
print(delete.to_string()) # "-D"
# Parse from string
kind = RowKind.from_string("+I")
assert kind == RowKind.INSERT
kind = RowKind.from_string("-D")
assert kind == RowKind.DELETE
# Byte-level check (performance optimization)
if RowKind.is_add_byte(0):
print("Byte 0 is INSERT")
if RowKind.is_add_byte(2):
print("Byte 2 is UPDATE_AFTER")
if not RowKind.is_add_byte(3):
print("Byte 3 is DELETE")
# Use with rows
from pypaimon.table.row.generic_row import GenericRow
row = GenericRow([1, "Alice", 30], fields, RowKind.INSERT)
if row.get_row_kind().is_add():
# Process addition
pass
# Merge logic example
def should_keep_record(row_kind: RowKind) -> bool:
"""Determine if record should be kept in final result."""
return row_kind.is_add()
# CDC processing
def process_cdc_event(event):
kind_str = event['op'] # e.g., "+I", "-D"
row_kind = RowKind.from_string(kind_str)
if row_kind == RowKind.INSERT:
# Handle insert
pass
elif row_kind == RowKind.UPDATE_BEFORE:
# Handle update before image
pass
elif row_kind == RowKind.UPDATE_AFTER:
# Handle update after image
pass
elif row_kind == RowKind.DELETE:
# Handle delete
pass