Skip to main content

A hybrid recommender system that grows with your data

Project description

kindling

A hybrid recommender that grows with your data — closed-form, no training loop, no GPU. One fused base score per (user, item) built from EASE / wilson-cooccurrence plus auto-gated z-normalized channels (trend, last-item, transitions, user-CF), with a Rust core for the numerics.

Design goals (learned the hard way — see docs/EXPERIMENTS.md):

  1. A wheel that imports is a wheel that works. numpy / pandas / scipy only; the linear algebra that matters (the EASE inversion) runs on a pure-Rust core (kindling_core). No PyTorch, no BLAS system deps.
  2. Closed-form shallow models, gated per dataset, beat speculative complexity. Every channel is closed-form or a counting statistic; every channel is activated by a measurable property of the data; every gate exists because the ungated version measurably hurt somewhere.

Install

pip install kindling-rec           # from PyPI
pip install -e ".[dev]"            # dev / from source
pip install -e ".[dev,bench]"      # + benchmark harness

Quickstart

from kindling import Engine
from kindling.loaders import movielens

interactions = movielens.load_1m()       # entity_id, item_id, timestamp[, rating]

engine = Engine()
engine.fit(interactions)

for rec in engine.recommend(entity_id=42, n=10):
    print(rec.item_id, rec.score, rec.base_kind)

# Many users at once — runs in parallel in the Rust core (GIL released).
batches = engine.recommend_batch([42, 99, 7], n=10)

Recommendation is served end-to-end by the Rust core (kindling_core): the EASE/cooc base, the channel blend, the boost layer, and cold-slots all run natively. Single recommend is sub-millisecond; batch is the parallel path.

New / anonymous users (absent from training) are served from ad-hoc seed items with no per-user training — and a zero/all-unknown seed set falls back to popularity:

engine.recommend_for_items(item_ids=[101, 205], n=10)   # personalized from seeds
engine.recommend_for_items(item_ids=[], n=10)           # → popularity fallback

Intelligent activation

Channels turn on by regime, not configuration. The base is EASE for catalogs ≤ 20k items and wilson-normalized cooccurrence above that; the trend channel needs timestamps; transitions additionally need the data not to be a rating-burst; user-CF activates only on sparse-history data; rating-weighting engages only when true ratings are present. Each decision is made from the data at fit() time. See docs/REFERENCE.md §2 for the gate table.

Where it stands (full-ranking NDCG@10, engine defaults)

Full results — discovery growth and the repeat-regime dominance — in docs/RESULTS.md.

dataset NDCG@10 notes
movielens-1m 0.293 rating-weighted EASE
amazon-beauty 0.033 + user-CF channel
steam (realistic tier) 0.066 open-catalog + cold slots
amazon-book-chrono 0.032 timestamps activate trend/transitions

Strongest personalized model on all four; beats implicit ALS everywhere; wins cold-user buckets on cold-heavy catalogs. The full benchmark record — including the negative results, which are half the value — is in docs/EXPERIMENTS.md.

On repeat-regime datasets (grocery/retail), a held-out gate turns on reorder recommendation; under repeat-aware eval kindling separates from the field — e.g. Dunnhumby 0.48 NDCG@10 vs ~0.05 for every baseline — while correctly declining on fake-repeat data like Steam (re-logs aren't repurchase). See docs/REPEAT-GATE.md. An opt-in EASE+ (EDLAE) base is available but off by default (docs/EASE-VARIANTS-ASSESSMENT.md).

Growth curves

How accuracy grows from cold to hot, against the standard baselines (bench/plot_growth_curves.py):

growth curves

Serving performance (native engine, bench/final_state_perf.py)

dataset fit single recommend p50 batch throughput NDCG@10
movielens-1m 4.2 s 0.17 ms 15.4k recs/s 0.2928
amazon-beauty 13.1 s 1.21 ms 3.0k recs/s 0.0328
steam 110 s 5.81 ms 0.8k recs/s 0.0659

The recommend path is pure Rust with the GIL released for the batch path — single recommend dropped from ~200 ms (the earlier Python path) to sub-millisecond, with byte-identical rankings.

Serving

Persist a fit as a self-contained artifact and serve it with no re-fit:

from kindling.serving import KindlingServer
KindlingServer.from_engine(engine).save("artifact/")
# ── in the serving process ──
server = KindlingServer.load("artifact/")
server.recommend("user-42", n=10)

A FastAPI example (kindling.serving_app) ships behind the optional serve extra: pip install 'kindling[serve]'.

Project layout

src/kindling/      library source (engine, serving, Rust bindings, loaders)
native/kindling_core/  Rust core (EASE, cooccurrence, channel blend, recommend)
bench/             regression gate (bench/verify.py) + frozen reports + plots
docs/              RESULTS.md (what it brings) · REFERENCE.md (architecture) ·
                   EXPERIMENTS.md (record) · LESSONS.md (what the build taught)
tests/             unit, property, integration

License

Apache 2.0.


kindling is an Awry Labs project — independent software, a little off on purpose.

Also from Awry Labs: Gravel — a C++/Python network-fragility library for measuring and stress-testing graph resilience. (GitHub)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kindling_rec-1.0.3.tar.gz (125.6 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

kindling_rec-1.0.3-cp311-abi3-win_amd64.whl (720.7 kB view details)

Uploaded CPython 3.11+Windows x86-64

kindling_rec-1.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (813.0 kB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

kindling_rec-1.0.3-cp311-abi3-macosx_11_0_arm64.whl (664.3 kB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

File details

Details for the file kindling_rec-1.0.3.tar.gz.

File metadata

  • Download URL: kindling_rec-1.0.3.tar.gz
  • Upload date:
  • Size: 125.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kindling_rec-1.0.3.tar.gz
Algorithm Hash digest
SHA256 822f1bb7c61cb190cf0c92dd12494b181be623407f792924f1455a3711641a9d
MD5 571caa9ac676d1fb9ebf6a8d87504a62
BLAKE2b-256 6719e4bd9f5ede0fa73fcbd6aa3b0b380609738ec1c708ff78facd8b93ce6e01

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.3.tar.gz:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.3-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: kindling_rec-1.0.3-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 720.7 kB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kindling_rec-1.0.3-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 9321bdf276c2a675611531566658d541dbff63213a1d3f638093549a872dee57
MD5 7ebe1296d2addb6e0152e25af686e168
BLAKE2b-256 9680a6ca6832b7004a2e5510ce7fb039a27934926ebf001dc5b84eecae21db5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.3-cp311-abi3-win_amd64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for kindling_rec-1.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2444bc0d923b7d957e362865c2a22aa3a2de41e99d0e9882dfa3d22be6fa06a6
MD5 fffa21aa89d8dbcffb943e17aed983ae
BLAKE2b-256 27dbcf9134b38df041102ed01d23dec58259a998a2ca005848b7aae01a771fe6

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kindling_rec-1.0.3-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for kindling_rec-1.0.3-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b532bab55fc5b4eca0ad647097136cac0f1f1d0f21c5abf9ced0ba05b593163b
MD5 3b307f381d16c8a32461b312c5a9d1d9
BLAKE2b-256 36ea644b6fc999cf45fd525ca9a3d4012393da134b18368b4044b70537e9a7f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for kindling_rec-1.0.3-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on rhoekstr/kindling

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page