Skip to main content

laurus-python

PyPI License: MIT

Python bindings for the Laurus search engine. Provides lexical search, vector search, and hybrid search from Python via a native Rust extension built with PyO3 and Maturin.

Features

  • Lexical Search -- Full-text search powered by an inverted index with BM25 scoring
  • Vector Search -- Approximate nearest neighbor (ANN) search using Flat, HNSW, or IVF indexes
  • Hybrid Search -- Combine lexical and vector results with fusion algorithms (RRF, WeightedSum)
  • Rich Query DSL -- Term, Phrase, Fuzzy, Wildcard, NumericRange, Geo, Boolean, Span queries
  • Text Analysis -- Tokenizers, filters, stemmers, and synonym expansion
  • Flexible Storage -- In-memory (ephemeral) or file-based (persistent) indexes
  • Pythonic API -- Clean, intuitive Python classes with full type information

Installation

pip install laurus

To build from source (requires Rust toolchain):

pip install maturin
maturin develop

Quick Start

import laurus

# Create an in-memory index
index = laurus.Index()

# Index documents
index.put_document("doc1", {"title": "Introduction to Rust", "body": "Systems programming language."})
index.put_document("doc2", {"title": "Python for Data Science", "body": "Data analysis with Python."})
index.commit()

# Search with a DSL string
results = index.search("title:rust", limit=5)
for r in results:
    print(f"[{r.id}] score={r.score:.4f}  {r.document['title']}")

# Search with a query object
results = index.search(laurus.TermQuery("body", "python"), limit=5)

Index Types

In-memory (ephemeral)

index = laurus.Index()

File-based (persistent)

schema = laurus.Schema()
schema.add_text_field("title")
schema.add_text_field("body")
schema.add_hnsw_field("embedding", dimension=384)

index = laurus.Index(path="./myindex", schema=schema)

This writes ./myindex/schema.toml and ./myindex/store/ -- the same layout laurus-cli create index --schema uses, so the directory can be opened by either. Reopening it later only needs the path (schema must be omitted, since it's loaded from the persisted schema.toml):

index = laurus.Index(path="./myindex")

A file-based index holds an exclusive lock on its directory for as long as the Index object is alive, so a second laurus.Index(path=...) on the same path fails while the first is still open. Call index.close() when you are done with an index -- especially before reopening the same path -- rather than relying on CPython's garbage collector, whose destruction timing is not guaranteed for every reference pattern (e.g. reference cycles). close() is idempotent; every other method raises after it has been called.

index.close()

Reloading an index

reload() picks up changes committed by another process without paying the cost of constructing a brand-new Index -- in particular, it reuses the already-loaded embedding model(s) when the schema's embedding configuration hasn't changed, instead of reloading them from scratch:

changed = index.reload()  # True if the commit generation actually advanced

reload() works whether the index is currently open or already close()d -- it reopens the same directory either way, so you can hold onto one Index object across a full reload cycle instead of constructing a new one and swapping references. It requires a file-backed index (path was given at construction); calling it on an in-memory index raises ValueError.

index.commit_generation() returns the same O(1) counter as stats()["commit_generation"], without stats()'s cost of scanning vector fields. It only reflects commits made through this Index object, though -- it's a snapshot held in memory, not re-read from disk on every call -- so it confirms whether reload() (or your own commit()) actually advanced the state, but it cannot by itself tell you whether another process has committed something new; only reload() picks that up.

To cheaply check for another process's changes without paying reload()'s cost, use the module-level laurus.peek_commit_generation(path). Unlike index.commit_generation(), it isn't tied to any Index object -- it reads commit_generation.json straight off disk, with no Engine construction at all, so it works even before you've opened an Index for that path in this process:

before = laurus.peek_commit_generation(path)
# ... later ...
if laurus.peek_commit_generation(path) != before:
    index.reload()

Raises ValueError if path isn't a laurus index directory (no persisted schema).

Durability / WAL

A persistent index writes every change to a write-ahead log (WAL). By default the WAL is fsync-ed on every record, so each write is fully durable. Opt into group commit to batch fsync for higher write throughput (a crash can lose up to the last unsynced batch, like SQLite's synchronous = NORMAL):

import laurus

policy = laurus.WalSyncPolicy.group(max_records=4096, max_interval_ms=1000)
index = laurus.Index(path="./myindex", schema=schema, wal_sync_policy=policy)

index.put_document("doc1", {"title": "Hello"})
index.flush_wal()  # force a durable barrier on demand
index.commit()     # also flushes the WAL

Omit wal_sync_policy (or pass laurus.WalSyncPolicy.per_record()) to keep the default per-record durability.

Query Types

Query class Description
TermQuery(field, term) Exact term match
PhraseQuery(field, [terms]) Ordered phrase match
FuzzyQuery(field, term, max_edits) Approximate term match
WildcardQuery(field, pattern) Wildcard pattern match (*, ?)
NumericRangeQuery(field, min, max) Numeric range (int or float)
GeoDistanceQuery.within_radius(field, lat, lon, distance_m) Geo-distance radius search
GeoBoundingBoxQuery.within_bounding_box(field, min_lat, min_lon, max_lat, max_lon) Geo bounding-box search
Geo3dDistanceQuery.within_sphere(field, x, y, z, distance_m) 3D ECEF sphere search
Geo3dBoundingBoxQuery.within_box(field, min_x, min_y, min_z, max_x, max_y, max_z) 3D ECEF AABB search
Geo3dNearestQuery.k_nearest(field, x, y, z, k) 3D ECEF k-nearest neighbours
BooleanQuery(must, should, must_not) Compound boolean logic
SpanNearQuery(field, [terms], slop) Proximity / ordered span match
VectorQuery(field, vector) Pre-computed vector similarity
VectorTextQuery(field, text) Text-to-vector similarity (requires embedder)
request = laurus.SearchRequest(
    lexical_query=laurus.TermQuery("body", "rust"),
    vector_query=laurus.VectorQuery("embedding", query_vec),
    fusion=laurus.RRF(k=60.0),
    limit=10,
)
results = index.search(request)

Fusion algorithms

Class Description
RRF(k=60.0) Reciprocal Rank Fusion (rank-based, default for hybrid)
WeightedSum(lexical_weight=0.5, vector_weight=0.5) Score-normalised weighted sum

Text Analysis

syn_dict = laurus.SynonymDictionary()
syn_dict.add_synonym_group(["ml", "machine learning"])

tokenizer = laurus.WhitespaceTokenizer()
filt = laurus.SynonymGraphFilter(syn_dict, keep_original=True, boost=0.8)

tokens = tokenizer.tokenize("ml tutorial")
tokens = filt.apply(tokens)
for tok in tokens:
    print(tok.text, tok.position, tok.boost)

Examples

Usage examples are in the examples/ directory:

Example Description
quickstart.py Basic indexing and full-text search
lexical_search.py All query types (Term, Phrase, Boolean, Fuzzy, Wildcard, Range, Geo, Span)
vector_search.py Semantic similarity search with embeddings
hybrid_search.py Combining lexical and vector search with fusion
synonym_graph_filter.py Synonym expansion in the analysis pipeline
search_with_openai.py Cloud-based embeddings via OpenAI
multimodal_search.py Text-to-image and image-to-image search

Documentation

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for laurus 0.13.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for laurus 0.13.2
File Size Uploaded
laurus-0.13.2.tar.gz 1.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for laurus 0.13.2
File
laurus-0.13.2-cp310-abi3-win_arm64.whl CPython 3.10 abi3 Windows ARM64 Details
laurus-0.13.2-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
laurus-0.13.2-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details
laurus-0.13.2-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details
laurus-0.13.2-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
laurus-0.13.2-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 60.0 MB

Release files / laurus-0.13.2.tar.gz

Download URL laurus-0.13.2.tar.gz
Size 1.5 MB
Tags Source
SHA-256 checksum
How to use checksums
e45834f6015ca064b57789a4d4c40616ab5c4b8e3429fe2b3db4f0716a228417
BLAKE2b-256 checksum
How to use checksums
a1cdaca3ac27b1173a4873cf5f5a9a70de1fdc5c2311b7fba39014c9ed4c3c52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-win_arm64.whl

Download URL laurus-0.13.2-cp310-abi3-win_arm64.whl
Size 9.2 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
1cc8a385b6977fa80d4e02dfa1e12577ef8a14552f642a76c12d69fab5c3b7e7
BLAKE2b-256 checksum
How to use checksums
6d8b3025b07c5d92b274b297881523de3936ea6cfe57c48c6d9466e759a30afe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-win_amd64.whl

Download URL laurus-0.13.2-cp310-abi3-win_amd64.whl
Size 9.7 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
54630b0a4207fd419fd2d89b0ce774382ddd6c2a86b9ba3017d32e6a0e7b287f
BLAKE2b-256 checksum
How to use checksums
3917fc744c68554e2f2677a59e50376e92d89dc70e3c1353f6aed539beaab300
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL laurus-0.13.2-cp310-abi3-manylinux_2_28_x86_64.whl
Size 10.3 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
c97e59ed3b2dec25a6247d76e5b57831802d545424666ac89632a537fd7ab5da
BLAKE2b-256 checksum
How to use checksums
4deaf19b2c663623705bd27f96a54ed0f2f07cac050dd420444c00900baea72a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL laurus-0.13.2-cp310-abi3-manylinux_2_28_aarch64.whl
Size 9.8 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
b0f60cc77c619d74365f19191d49b599a280dcf656e5057b4d6b72496e891b6a
BLAKE2b-256 checksum
How to use checksums
2632d81097296db3846c58ebb68df28f668330090cfabc6a6c77e6fd96a63cba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-macosx_11_0_arm64.whl

Download URL laurus-0.13.2-cp310-abi3-macosx_11_0_arm64.whl
Size 9.4 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
ca36f153b54efd67418794be05dd4c5fa8bc2451ed0c413506da9683d3f10c5e
BLAKE2b-256 checksum
How to use checksums
7a6a10601bde98ca6a0fa8ab8475821c9c750f6c69bf3734d4ea14042670ed74
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / laurus-0.13.2-cp310-abi3-macosx_10_12_x86_64.whl

Download URL laurus-0.13.2-cp310-abi3-macosx_10_12_x86_64.whl
Size 10.0 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
315da5e867095b7f8edfb65169c547e2ba2313f4d59caee445132a19f977db14
BLAKE2b-256 checksum
How to use checksums
ae1d657b5ca9762d3b9f74155e33016123223a6820c0f5fe699555e82c00dad3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.13.2 This release

7 release files

0.12.1

7 release files

0.9.0

7 release files

0.8.0

7 release files

0.7.0

7 release files

0.6.0

7 release files

0.5.0

7 release files

0.4.2

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page