Skip to main content

Fast BM25 full-text search with substring matching, fuzzy search, and regex — powered by Rust

Project description

lucivy

Fast BM25 full-text search for Python — with substring matching, fuzzy search, regex, and highlights. Powered by Rust.

Install

pip install lucivy

Quick start

import lucivy

index = lucivy.Index.create("./my_index", fields=[
    {"name": "title", "type": "text"},
    {"name": "body", "type": "text"},
])

index.add(1, title="Rust Programming", body="Systems programming with memory safety")
index.add(2, title="Python Guide", body="Data science and web development")
index.commit()

results = index.search("programming", highlights=True)
for r in results:
    print(r.doc_id, r.score, r.highlights)

API

Create / open

# Create a new index
index = lucivy.Index.create("./my_index", fields=[
    {"name": "title", "type": "text"},
    {"name": "body",  "type": "text"},
    {"name": "tag",   "type": "keyword"},
    {"name": "year",  "type": "u64"},
])

# Open an existing index
index = lucivy.Index.open("./my_index")

# Context manager (auto-commit on exit)
with lucivy.Index.open("./my_index") as index:
    index.add(3, title="New doc", body="content")

Add / update / delete

index.add(1, title="Hello", body="World")
index.add_many([
    {"doc_id": 2, "title": "Foo", "body": "Bar"},
    {"doc_id": 3, "title": "Baz", "body": "Qux"},
])
index.update(1, title="Updated title", body="Updated body")
index.delete(2)
index.commit()

Search

# String query — each word is searched across all text fields (contains_split)
results = index.search("rust async programming")

# Options
results = index.search("rust", limit=20, highlights=True, allowed_ids=[1, 3, 5])

# Retrieve stored field values with results
results = index.search("rust", fields=True)
for r in results:
    print(r.doc_id, r.fields['title'], r.fields['body'])

contains — substring, fuzzy, regex (cross-token)

Searches stored text, not individual tokens. Handles multi-word phrases, substrings, typos, and regex across token boundaries.

# Substring — matches "programming", "programmer", etc.
index.search({"type": "contains", "field": "body", "value": "program"})

# Multi-word phrase
index.search({"type": "contains", "field": "body", "value": "memory safety"})

# Fuzzy (catches typos, distance=1 by default)
index.search({"type": "contains", "field": "body", "value": "programing languag", "distance": 1})

# Regex on stored text
index.search({"type": "contains", "field": "body", "value": "program.*language", "regex": True})

contains_split — one word = one contains query, OR'd together

Like a string query but targeting a specific field.

# "rust safety" → contains("rust") OR contains("safety") on body
index.search({"type": "contains_split", "field": "body", "value": "rust safety"})

# With fuzzy distance — each word gets fuzzy tolerance
index.search({"type": "contains_split", "field": "body", "value": "memry safty", "distance": 1})

boolean — combine queries with must / should / must_not

index.search({
    "type": "boolean",
    "must": [
        {"type": "contains", "field": "body", "value": "rust"},
    ],
    "should": [
        {"type": "contains", "field": "title", "value": "guide"},
    ],
    "must_not": [
        {"type": "contains", "field": "body", "value": "deprecated"},
    ],
})

keyword / range — for non-text fields

index.search({"type": "keyword", "field": "tag", "value": "rust"})
index.search({"type": "range", "field": "year", "gte": 2020, "lte": 2025})

Snapshots (export / import)

# Export index to a .luce file
index.export_snapshot_to("./backup.luce")

# Import from .luce file
restored = lucivy.Index.import_snapshot_from("./backup.luce", dest_path="./restored_index")

# Import from bytes
with open("./backup.luce", "rb") as f:
    restored = lucivy.Index.import_snapshot(f.read(), dest_path="./restored_index")

Info

index.num_docs()  # number of documents
index.path()      # index directory path
index.schema()    # list of field definitions

License

MIT

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

lucivy-0.3.2.tar.gz (10.7 MB view details)

Uploaded Source

Built Distribution

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

lucivy-0.3.2-cp313-cp313-manylinux_2_34_x86_64.whl (2.8 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ x86-64

File details

Details for the file lucivy-0.3.2.tar.gz.

File metadata

  • Download URL: lucivy-0.3.2.tar.gz
  • Upload date:
  • Size: 10.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for lucivy-0.3.2.tar.gz
Algorithm Hash digest
SHA256 a13a119334ec52754e55c8662a86d99ab5b82af5ff4fef05d7b03ab9c8a84568
MD5 fd8ca2a633e198b18b26a401108dcd27
BLAKE2b-256 3b8ca453fc0357af0440eff1ea435df68d660e824213686d1e83770102b15924

See more details on using hashes here.

File details

Details for the file lucivy-0.3.2-cp313-cp313-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for lucivy-0.3.2-cp313-cp313-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 7636a4ba88616e6e910686178d4c29f19da5dc6b10cb65da303b72a69f4ebd47
MD5 e8b03e684c38c660191c606e4cff6b3a
BLAKE2b-256 ce42f213f453e52dbe73e225c6e9113fac1d4ebd655619c1f05ace5d2c575008

See more details on using hashes here.

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