Skip to main content

Building a Linked OCEL

Construct an OCEL end-to-end: Declare event and object types, add events/objects with E2O/O2O relations, and export the resulting OCEL 2.0 to different formats.

SlimLinkedOCEL is a compact representation of an object-centric event log. It is designed for efficient in-memory construction and usage. Events and objects are represented by integer IDs (i.e., their index in the event/object list), and relationships are stored separately, which allows quickly identifying all related events/objects without scanning through the whole dataset. The slim_ocel_bindings module exposes its core functionality to Python, so you can build a log and export it to OCEL 2.0.

The script below builds a small log (one event type place order with a tip attribute; two object types order and item, where item has a price attribute; then 100 events, each with a new order and four items wired up via E2O and O2O), reads a few values back, and exports the result. The ev, order, item variables returned by the locel_add_* calls are the integer refs themselves: Each is the index of that element in the log. Every locel_get_* and locel_delete_* function takes such a ref.

Script

"""
Build, query, and export a SlimLinkedOCEL log.

Run:     python example.py
Install: pip install r4pm
"""

import r4pm
import r4pm.bindings as b

# --- Build ---

locel = b.locel_new()

# One event type with a `tip` attribute.
b.locel_add_event_type(locel, "place order", [{"name": "tip", "type": "float"}])

# Two object types. `item` has a `price` attribute.
# (Object attributes are always time-indexed in OCEL 2.0.)
b.locel_add_object_type(locel, "order")
b.locel_add_object_type(locel, "item", [{"name": "price", "type": "float"}])

# 100 events. Each event gets its own order plus four items.
# The ints returned by `locel_add_event` / `locel_add_object` are the refs:
# each is the index of that element in the log. All query functions take these.
for i in range(100):
    ev = b.locel_add_event(
        locel,
        "place order",
        "2026-03-02T10:30:00Z",
        None,
        [round(i * 0.5, 2)],  # tip
    )
    order = b.locel_add_object(locel, "order")
    b.locel_add_e2o(locel, ev, order, "of")

    for j in range(4):
        # Each object attribute takes a list of (timestamp, value) tuples.
        # For initial or constant values, use UNIX epoch.
        price_history = [[("1970-01-01T00:00:00Z", round(j * 4.3, 2))]]
        item = b.locel_add_object(locel, "item", None, price_history)
        b.locel_add_e2o(locel, ev, item, "with")
        b.locel_add_o2o(locel, item, order, "is in")

# --- Export ---
# File extension picks the format (see "Export formats" below).
r4pm.export_item(locel, "export.xml")


# --- Read back / Use ---
# How many events of a given type?
events = b.locel_get_evs_of_type(locel, "place order")
print(f"{len(events)} 'place order' events")
# -> 100 'place order' events

# Read an attribute off the most recently added event.
tip = b.locel_get_ev_attr_val(locel, ev, "tip")
print(f"last event tip = {tip}")
# -> last event tip = 49.5

# Walk the E2O relations of that event and show what it's linked to.
for qualifier, ob_ref in b.locel_get_e2o(locel, ev):
    ob_type = b.locel_get_ob_type_of(locel, ob_ref)
    print(f"  {qualifier} -> {ob_type} (ref {ob_ref})")
# ->   of -> order (ref 495)
# ->   with -> item (ref 496)
# ->   with -> item (ref 497)
# ->   with -> item (ref 498)
# ->   with -> item (ref 499)

Export formats

r4pm.export_item picks the output format from the file extension:

  • .xml OCEL 2.0 XML
  • .sqlite OCEL 2.0 SQLite
  • .json OCEL 2.0 JSON

To write a SQLite database instead of XML, change the corresponding line to r4pm.export_item(locel, "export.sqlite").