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.1-cp311-cp311-win_amd64.whl (542.3 kB view details)

Uploaded CPython 3.11Windows x86-64

lab_1806_vec_db-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.1 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.1-cp310-cp310-win_amd64.whl (542.4 kB view details)

Uploaded CPython 3.10Windows x86-64

lab_1806_vec_db-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.1-cp39-cp39-win_amd64.whl (542.6 kB view details)

Uploaded CPython 3.9Windows x86-64

lab_1806_vec_db-0.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (746.0 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.1-cp38-cp38-win_amd64.whl (542.3 kB view details)

Uploaded CPython 3.8Windows x86-64

lab_1806_vec_db-0.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.8 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 1854eae352d7a3a24db3d58e444d0ce3a009134300526ae49746054988ffe62c
MD5 ce5635349d06dce1542ae1e7f5e8ccce
BLAKE2b-256 58452bbf398c0426e7cc90afb3bbd97e092383eefe3e5c466c52e4cd705fec46

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0e3a27de091befc96131ac4c2c987541bfc28dea26e6d610feab678de40979bf
MD5 26100fcd830dec3ab572b2d2530492c2
BLAKE2b-256 3534cb3b66c87cd9ebb9d444478289be6693362d8fb393e4c65a633597748126

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 4bd9acaf45832e0978cb28ccc105ab02f7cce11867d249a49034ac7ca3e72290
MD5 2ee90864c95873dede1210c77d013ccc
BLAKE2b-256 8b42de137a8b795682c900a849bee45f3d619a610b2357891364ec838178857a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b67ebdda8075fd3d14ee7512417c3a39bc855e5f85d43e3dc76751dde54ede49
MD5 13bf72d0ff32dd9e6a24b767b84d72b1
BLAKE2b-256 a3dc9a3ab695844e546e5f074382b8e187ebee4d34afbfef442993bf7a9c2286

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 da13531808fa53ec0bad4674f25e39756f2281369cf5651c784f81f88e5662bd
MD5 f27f6567f89151aa019e3fc7f5d96c00
BLAKE2b-256 115a2b42882d8b46d1416210b1329c96ec049e45610526354445a69701f611f5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 60885c37143f049e0c0fc76880944576b981bf10c745df0ec1ef206a8ee716c5
MD5 e58e5e02f91ae8ab1229fb7aee634cbb
BLAKE2b-256 2ad34db86dade1487d93ec89475589eaf747892c26a78540b2abedbce6bfd08a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 04a0ee6d2c5cb88b14a231e462b2cf23813b22a19218c19e2ab7f96a98c2670b
MD5 df8bc5315592a8557438b51fd3b620c5
BLAKE2b-256 4d29d22f76e04e8c3e8924b015892307d9c0edf5256359ee42e4445a2d118dc4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2a3457b416f16432162a54138bc5718c8faca0ef36578ced7f608ad78272bd4c
MD5 18ef5a4d575c95603fe0a77700651e7f
BLAKE2b-256 6fa9344c3f4fe7f151eb6ce078f74eba9c93263b4d0bd22ff6f3444818c1b0c9

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