The performance of flatdata-py depends heavily on the access pattern used.
Iteration (Slow for bulk operations)
Iterating over a vector (e.g., for x in archive.links) yields one Python object per element. This incurs significant per-element overhead because each field access must unpack bits from the memory-mapped data.
Vectorized Access (Fast for bulk operations)
For high-performance bulk operations, use vectorized methods that read fields directly into NumPy arrays or Pandas DataFrames. This avoids the per-element Python object overhead.
Best Practices:
- Single column access: Use
vector.field_name to get a Pandas DataFrame of a specific field. This is most efficient when you only need one or a few fields. - Full row access: Use
vector.to_numpy() or vector.to_data_frame() when you need all fields in a vector at once. - Slicing: Slices work with vectorized methods (e.g.,
vector[1000:2000].to_numpy()). - Random access: Use
vector[i].field for accessing individual elements by index.
Note: The underlying data is memory-mapped; the OS pages it from disk on demand. Vectorized results are materialized as NumPy arrays in RAM.
# SLOW: Iterating over a vector
count = sum(1 for x in archive.links if x.speed_limit > 100)
# FAST: Single column access (returns a pandas DataFrame)
df = archive.links.speed_limit
count = len(df[df['speed_limit'] > 100])
# FAST: Full NumPy structured array
arr = archive.links.to_numpy()
count = int(np.sum(arr['speed_limit'] > 100))
# FAST: Slices work too
arr = archive.links[1000:2000].to_numpy()
df = archive.links[::10].to_data_frame()