Core
Cross-cutting concerns used by all layers.
Settings
Configuration from environment variables.
from ftm_lakehouse.core.settings import Settings
settings = Settings()
print(settings.uri) # LAKEHOUSE_URI
print(settings.journal_uri) # LAKEHOUSE_JOURNAL_URI
ftm_lakehouse.core.settings.Settings
Bases: BaseSettings
Source code in ftm_lakehouse/core/settings.py
journal_pool_size = 5
class-attribute
instance-attribute
Postgres journal connections kept warm between writers
(LAKEHOUSE_JOURNAL_POOL_SIZE). 0 pools nothing. It is per dataset: a
worker writing many datasets holds up to this many idle connections for each
of them, which is the figure to size against postgres
max_connections.
lock_max_retries = 22
class-attribute
instance-attribute
Retry bound when acquiring the dataset write fence (.LOCK). Retry
n sleeps n + rand(0, 1) seconds, so the total wait is roughly
N²/2 seconds – the default of 22 gives up after ~4.5 minutes; a lock
left behind by a crashed writer must be released via ftm-lakehouse
operations unlock.
zfs_pool = None
class-attribute
instance-attribute
ZFS dataset path the lakehouse's tuned datasets are created under.
Transport / agent configuration (socket, owner, peer auth) lives in the
external zfs-agent package's own ZFS_* environment.
Path Conventions
Standard paths within the lakehouse.
Path conventions for the FollowTheMoney data lakehouse.
The fundamental idea is to have a convention-based file system layout with well-known paths for metadata and information interchange between processing stages.
All paths are dataset-relative unless otherwise noted.
Dataset Layout
::
lakehouse/
index.json # catalog index
config.yml # catalog configuration
versions/ # versioned snapshots
YYYY/MM/YYYY-MM-DDTHH:MM:SS/
index.json
config.yml
[dataset]/
index.json # dataset index
config.yml # dataset configuration
versions/ # versioned snapshots
YYYY/MM/...
.LOCK # dataset-wide maintenance lock
.LOCK-APPENDS/ # in-flight append markers
.locks/{tenant}/ # operation-specific locks
tags/{tenant}/ # workflow state / cache
archive/ # content-addressed file storage
ab/cd/ef/{checksum}/ # SHA256 split into segments
blob # file blob (stored once)
{file_id}.json # metadata (one per source path)
{origin}.txt # extracted text (one per engine)
statements/ # statement store (shard-partitioned)
shard={shard}/
bucket={bucket}/
origin={origin}/
*.parquet
entities.ftm.json[.zst|gzip] # aggregated entities export
exports/
statistics.json # entity counts, facets
statements.csv[.zst|gzip] # sorted statements
documents.csv[.zst|gzip] # document metadata
documents.{origin}.csv[...] # document metadata (origin-scoped)
graph.cypher # neo4j export (optional)
diffs/ # dirs are codec-free (they double
entities.ftm.json/ # as freshness tags); the files
{ts}.delta.json[.zst|gzip] # entities delta
exports/
documents.csv/
{ts}.diff.csv[.zst|gzip] # documents delta
documents.{origin}.csv/
{ts}.diff.csv[.zst|gzip] # origin-scoped delta
jobs/
runs/
{job_type}/
{timestamp}.json # job run results
CONFIG = StoreKey('config.yml')
module-attribute
user editable config filename
INDEX = StoreKey('index.json')
module-attribute
generated index filename
ARCHIVE = 'archive'
module-attribute
Base path for archive
STATEMENTS = 'statements'
module-attribute
Base path for storing statement data (partitioned by shard, bucket, origin)
EXPORTS = StoreKey('exports')
module-attribute
Base path for exports
Tag Conventions
Standard tags for freshness tracking.
Global tags used to identify actions. Used for cache keys of workflow runs etc.
Export operations don't have constants here – their freshness tag is the
path.* export target itself (e.g. exports/statements.csv), touched
by DatasetJobOperation._run_local after a successful run.
JOURNAL_UPDATED = 'journal/last_updated'
module-attribute
Statement journal was updated
JOURNAL_FLUSHED = 'journal/last_flushed'
module-attribute
Journal store last flushed into statement store
STATEMENTS_UPDATED = 'statements/last_updated'
module-attribute
Statement store was updated
STATEMENTS_OPTIMIZED = 'statements/last_optimized'
module-attribute
Statement store was optimized (merge + compact + vacuum)
ARCHIVE_UPDATED = 'archive/last_updated'
module-attribute
Archive last updated (file added or removed)