Skip to main content

No project description provided

Project description

lab-1806-vec-db

Lab 1806 Vector Database.

Getting Started with Python

# See https://pypi.org/project/lab-1806-vec-db/
pip install lab-1806-vec-db

Warning: All the arguments are positional, DO NOT use keyword arguments like upper_bound=0.5.

Basic Usage

VecDB is recommended for most cases as a high-level API.

Low-level APIs are also provided. But before using them, make sure you know what you are doing.

BareVecTable is a low-level API designed for a single table without auto-saving or multi-threading support.

calc_dist is a helper function to calculate the distance between two vectors. It supports "cosine" and "l2sqr", default to "cosine". To make sure smaller is closer, we make cosine_dist = 1 - cosine_similarity.

import os

from lab_1806_vec_db import BareVecTable, VecDB, calc_dist


def test_calc_dist():
    print("\n[Test] calc_dist")
    a = [0.3, 0.4]
    b = [0.4, 0.3]

    # norm_a = sqrt(0.3^2 + 0.4^2) = 0.5
    # norm_b = sqrt(0.4^2 + 0.3^2) = 0.5
    # dot_product = 0.3 * 0.4 + 0.4 * 0.3 = 0.24
    # cosine_dist = 1 - (a dot b) / (|a| * |b|)
    #             = 1 - 0.24 / (0.5 * 0.5) = 0.04

    cosine_dist = calc_dist(a, b)
    print(f"{cosine_dist=}")
    assert abs(cosine_dist - 0.04) < 1e-6, "Test failed"


test_calc_dist()


def test_bare_vec_table():
    print("\n[Test] BareVecTable")
    table = BareVecTable(dim=4)
    table.add([1.0, 0.0, 0.0, 0.0], {"content": "a"})
    table.add([0.0, 1.0, 0.0, 0.0], {"content": "b"})
    table.add([0.0, 0.0, 1.0, 0.0], {"content": "c"})

    table.batch_add(
        [[1.0, 0.0, 0.0, 0.1], [0.0, 1.0, 0.0, 0.1], [0.0, 0.0, 1.0, 0.1]],
        [{"content": x} for x in ["aa", "bb", "cc"]],
    )
    # Save and load <<<<
    table.save("test_table.local.db")
    table = BareVecTable.load("test_table.local.db")
    os.remove("test_table.local.db")
    # Save and load >>>>

    results = table.search([1.0, 0.0, 0.0, 0.0], 2)
    contents: list[str] = []
    for metadata, d in results:
        print(metadata["content"], d)
        contents.append(metadata["content"])
    assert (contents[0], contents[1]) == ("a", "aa"), "Test failed"
    print("Test passed")


test_bare_vec_table()


def test_vec_db():
    print("\n[Test] VecDB")
    db = VecDB("./tmp/vec_db")
    for key in db.get_all_keys():
        db.delete_table(key)

    keys = db.get_all_keys()
    assert len(keys) == 0, "Test failed"

    db.create_table_if_not_exists("table_1", 4)
    db.add("table_1", [1.0, 0.0, 0.0, 0.0], {"content": "a"})
    db.add("table_1", [0.0, 1.0, 0.0, 0.0], {"content": "b"})
    db.add("table_1", [0.0, 0.0, 1.0, 0.0], {"content": "c"})

    db.create_table_if_not_exists("table_2", 4)
    db.batch_add(
        "table_2",
        [[1.0, 0.0, 0.0, 0.1], [0.0, 1.0, 0.0, 0.1], [0.0, 0.0, 1.0, 0.1]],
        [{"content": x} for x in ["aa", "bb", "cc"]],
    )

    result = db.search("table_1", [1.0, 0.0, 0.0, 0.0], 3, None, 0.5)
    print(result)
    assert len(result) == 1, "Test failed"
    assert result[0][0]["content"] == "a", "Test failed"

    results = db.join_search({"table_1", "table_2"}, [1.0, 0.0, 0.0, 0.0], 2)

    for key, metadata, d in results:
        print(key, metadata["content"], d)

    assert len(results) == 2, "Test failed"
    assert results[0][0] == "table_1", "Test failed"
    assert results[0][1]["content"] == "a", "Test failed"
    assert results[1][0] == "table_2", "Test failed"
    assert results[1][1]["content"] == "aa", "Test failed"
    print("Test passed")


test_vec_db()

About auto-saving

Safe to interrupt the process on Python Level at any time with Exception or KeyboardInterrupt.

import os

from lab_1806_vec_db import VecDB

if os.path.exists("./tmp/vec_db"):
    for file in os.listdir("./tmp/vec_db"):
        os.remove(f"./tmp/vec_db/{file}")
# Wait for the user to see the empty dir
input("Press Enter to continue...")


# Create the database
db = VecDB("./tmp/vec_db")
db.create_table_if_not_exists("table_1", 1)
db.add("table_1", [0.0], {"content": "0"})


# Data will be written to the disk every 30 seconds
# Here we can see the dir contains a lock file.
# And after 5 seconds, the `brief.toml` will be created
# And after 30 seconds, `*.db` files will be created

# Try interrupting the process at different stages
# And check if the data appears in the disk at last

# Cases:
# - Wait for 30 seconds without doing anything
# - Enter to exit normally
# - Type "raise" to raise an exception
# - Type "dim" to do a wrong operation
# - Press Ctrl+C to interrupt the process

cmd = input("Type to choose the action: ")
if cmd == "":
    exit(0)  # Exit normally
elif cmd == "raise":
    raise Exception("Deliberate exception")
elif cmd == "dim":
    # Dimension mismatch
    db.add("table_1", [0.0, 1.0], {"content": "0, 1"})
elif cmd == "len":
    # Length mismatch
    db.batch_add("table_1", [[0.0], [1.0]], [{"content": "0"}])

# File appears before the program exits in all cases, even with Exception or KeyboardInterrupt

About multi-threading

VecDB is thread-safe. You can use it in multiple threads, and it will handle the lock automatically.

When methods on VecDB is called, GIL will be temporarily released, so other threads can run Python code.

import random
import threading
import time

from lab_1806_vec_db import VecDB

# Add `std::thread::sleep(std::time::Duration::from_secs(1));` to VecDBManager::search().

"""Sample output:
0.0s: Before search 1
0.6s: Before search 2
1.0s: After search 1
1.2s: Before search 3
1.6s: After search 2
1.8s: Before search 4
2.2s: After search 3
2.8s: After search 4
"""

db = VecDB("tmp/vec_db")

db.create_table_if_not_exists("table1", 1)
db.batch_add(
    "table1",
    [[random.random()] for _ in range(100)],
    [{"id": str(i)} for i in range(100)],
)

count = 0
start = time.time()


def worker():
    global count

    count += 1
    id = f"{count}"
    print(f"{time.time()-start:0.1f}s: Before search {id}")
    db.search("table1", [random.random()], 1)
    print(f"{time.time()-start:0.1f}s: After search {id}")


threads = []
for _ in range(4):
    t = threading.Thread(target=worker)
    threads.append(t)
    t.start()
    time.sleep(0.6)

for t in threads:
    t.join()

Development with Rust

# Install Rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
. "$HOME/.cargo/env"

# Then install the rust-analyzer extension in VSCode.
# You may need to set "rust-analyzer.runnables.extraEnv" in VSCode Machine settings.
# The value should be like {"PATH":""} and make sure that `/home/YOUR_NAME/.cargo/bin` is in it.
# Otherwise you may fail when press the `Run test` button.

# Run tests
# Add `-r` to test with release mode
cargo test
# Or you can click the 'Run Test' button in VSCode to show output.
# Our GitHub Actions will also run the tests.

Test the python binding with test_pyo3.py.

# Install Python 3.10
brew install python@3.10
# or on Windows
scoop bucket add versions
scoop install python310

# Install uv.
# See https://github.com/astral-sh/uv for alternatives.
pip install uv
# or on Windows
scoop install uv

# Run the Python test
uv sync --reinstall-package lab_1806_vec_db
uv run -m examples.test_pyo3

# Build the Python Wheel Release
# This will be automatically run in GitHub Actions.
uv build

Examples Binaries

See also the Binaries at src/bin/, and the Examples at examples/.

  • src/bin/convert_fvecs.rs: Convert the fvecs format to the binary format.
  • src/bin/gen_ground_truth.rs: Generate the ground truth for the query.
  • examples/bench.rs: The benchmark for index algorithms.

Check the comments at the end of the source files for the usage.

Dataset

Download Gist1M dataset from:

Then, you can run the examples to test the database.

Note that pre-built index file may be outdated and failed to load. You can build it yourself.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

lab_1806_vec_db-0.5.0-cp311-cp311-win_amd64.whl (542.1 kB view details)

Uploaded CPython 3.11Windows x86-64

lab_1806_vec_db-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (744.3 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.0-cp310-cp310-win_amd64.whl (542.0 kB view details)

Uploaded CPython 3.10Windows x86-64

lab_1806_vec_db-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (744.7 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.0-cp39-cp39-win_amd64.whl (542.4 kB view details)

Uploaded CPython 3.9Windows x86-64

lab_1806_vec_db-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.6 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.0-cp38-cp38-win_amd64.whl (542.0 kB view details)

Uploaded CPython 3.8Windows x86-64

lab_1806_vec_db-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.3 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

Details for the file lab_1806_vec_db-0.5.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 f16655611b7cc5fee9a7e989409d59e8ecc14e9763ee45477ac3b6abab9254c8
MD5 6b9dad08c2516d9175678eed6c645734
BLAKE2b-256 109fd30062fcbf6ae54989e65b69d4a0118a20d5c7e0792e30733f5e3b8a07dc

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fcc79aa4bcc2a387452181eb809322cf330fd5d8b9a49473b0e8919776ef2075
MD5 d7db3aedb12ad49eefaea2fc6c544767
BLAKE2b-256 6589358ad8b177be5eec301246fc8af29fc11ac14730ef5c8c7d1282c951ef67

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 5c76f95c2c6bcaa7008fee5980dde22e045bcbb07431dbcd01b1efd626da6646
MD5 3f66b032c36c54eb992ab03779171d4e
BLAKE2b-256 c6df94a65a534dce18675ccaa93d9e20fb25db09cc99bf3ae2b3bcf4bcd8f66f

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 62ca21e9474fe0afa6b9acbd16e4d4cea63a616a322c8ac45650c3557171dcb0
MD5 9c73be05c64ae38384a0be8b2855e2a6
BLAKE2b-256 128e366afd7091ff974252946f6bfd7893419d3ee1f5dca3b6db958151d71e19

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp39-cp39-win_amd64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 61d16ef5c00de13dee30b027423a346e2076f10f2b641bdf561c3496c70d833e
MD5 151edc8107a9d39bc73157fc52045618
BLAKE2b-256 bfe3201ba3f9b57773e877b597d68c5ebc62bcd5e92cb3fe3e4d6bdb23aedccf

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 029cccab83d4149d4e7018fabb926ef77406afda64434d49e1e90aef9b813c7f
MD5 edb02dd1667a20bf2ce888cc54808c82
BLAKE2b-256 b5650dc91f4bf8610812b11c9e0045185b9abed249ceb01be7a1a56b5436f6d8

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp38-cp38-win_amd64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 52a5dda1cc2db5a0747e72f550aade5ea31867b342b75d14f3b22b536e1c6e5e
MD5 d7affc6c0725e9ffd1769920e8c47bc0
BLAKE2b-256 57b338516050fc419fa1be6772db0309da699edd627b1abb0be2b9683bba216b

See more details on using hashes here.

File details

Details for the file lab_1806_vec_db-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 86b7e0001a0c3740e1455d13d812e36c1abc42c9a420d2138935a089fbec45f7
MD5 16c5e02d05101b2aa76102f9e6f74f95
BLAKE2b-256 599458763b10141ec3546851c7db705be498565c922cb3a7fbef72d13240a16a

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