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

Uploaded CPython 3.11Windows x86-64

lab_1806_vec_db-0.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (742.1 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.3-cp310-cp310-win_amd64.whl (538.2 kB view details)

Uploaded CPython 3.10Windows x86-64

lab_1806_vec_db-0.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (742.2 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.3-cp39-cp39-win_amd64.whl (538.5 kB view details)

Uploaded CPython 3.9Windows x86-64

lab_1806_vec_db-0.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (743.1 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.3-cp38-cp38-win_amd64.whl (538.2 kB view details)

Uploaded CPython 3.8Windows x86-64

lab_1806_vec_db-0.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (742.5 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 cb068ec6389e3cf948e4bb827aa376198570cf82cf63822c6ec3c8ef84ec10b3
MD5 9c93ab3cf0090c371a34480ae66d9d5e
BLAKE2b-256 443e0bae09906cd93329239b69a1abd63b5d95f42e8a5158ee05b4db26316477

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 388db1cfe02f44616c066ec36e4bc1c75d7e38ebd13831ea91f1dfbf6afe9b06
MD5 abad73806e612b648f3164d6d9604cd3
BLAKE2b-256 325ff15915eecef82996f25d788df2746c731b13aa37c2ffa5c89724ec1cb8cb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 4938b54c8b14159ae73695717445e8c0b5509674ff99b7944993695469a144cb
MD5 ef6ec8059b46980ba671142b5759b01d
BLAKE2b-256 3fcbcc9027cea332ad90da1d14db40f707407d1995b78b5dc1e083f9e962d4df

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 44839f6220a105e396b21d24719b8841526f6802e9c3ad0727442b9dfbc3d857
MD5 6e89a7d7d08a3bbfa2495ef09a70731d
BLAKE2b-256 5b6aea34c32168b2a981db53581f19503ce5df4b26ec82e679bd2fa9c2b6cd69

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 696f5411628d2b9e57642888978f045c9656927ed024e7c4e5e316816cfaa21b
MD5 02258e9722312fb70818716b1d892ab2
BLAKE2b-256 945e3b068375a64cfbdec27d98c5ba8e641952218ea9604950481ce2c62c2eda

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a9ccdcf93ef919f3f7e4e4f42e4cc9b4d540c022da651dc0295f9d10a3ada93a
MD5 09ede431f45278fb0bdba39ef11bfa3b
BLAKE2b-256 ab2ccdb47bf80c4a3edbecba4f94f4eb2ce1253bd5b4660fb31eba32387f1f2d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 6691dcbed00188eba88307ac416220d5d37720361a407eb069170affd0f52f51
MD5 46789e2128592320fb2b92179c65b60b
BLAKE2b-256 af6db8e428a520841fef689211232d4004e8b32bd8a201c3334f15835f2e8eec

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 79d47c5971f4c1f4af0f332716c0d5dd924769edbfa036e8a1c4fa8dc06cd18a
MD5 2bf41b4415c5253eec5b683db5fe13df
BLAKE2b-256 4e902eb15be156d341296bf0f68030da0963c04b1cfa9c8d32783903b2949897

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