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

Uploaded CPython 3.11Windows x86-64

lab_1806_vec_db-0.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (742.3 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.2-cp310-cp310-win_amd64.whl (538.0 kB view details)

Uploaded CPython 3.10Windows x86-64

lab_1806_vec_db-0.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (742.5 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.2-cp39-cp39-win_amd64.whl (538.4 kB view details)

Uploaded CPython 3.9Windows x86-64

lab_1806_vec_db-0.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (743.3 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

lab_1806_vec_db-0.5.2-cp38-cp38-win_amd64.whl (538.0 kB view details)

Uploaded CPython 3.8Windows x86-64

lab_1806_vec_db-0.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (743.0 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 5afd8bdc89c9f86fb075b45971069f76895c6904b8a3aaa7971da9b6dc4b857e
MD5 97f03b18fffd28d7e43c49cde4979537
BLAKE2b-256 75c547abfde0cbca00ae20f39f6be8bfd93e7a8586c0d0a0f6e7271f02f8c350

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0c4da2251b195de961310cf967f52bcf37930a4bd36978a3c84777a04c1be6f9
MD5 4f659480d5c28067bb2f9e3eb2c1aff9
BLAKE2b-256 a0d7e63a8edad9dc7b55d7b3bde61bcdad437def9ea00ce4ac58d357697181be

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 460dc3154ae77d53b08b551edfcc9fdd0cb2f530fbb4e372ea16ced755b8c081
MD5 da283b5277a0e121954171b8ead9bcdb
BLAKE2b-256 22d07c10d01bbc2ca4f157c6185d658ecf0cdd072f922f57d661c03f91430a57

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 beb4f26f5f59ed1130c8bea1d4145d99cb2b76b2b12e3a36843fc10dd27b5adc
MD5 057c098209c60acaeed7d78f90754f50
BLAKE2b-256 79515cccffdea6093c94111e0ead164f7347ce688d4ea609c630931222e6afec

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 0317c7fc43b2b79d5938945ff99dfcfb727710a2e7f77466ca1832cb59e4fcaf
MD5 d942f31fa8df1fc547391e48e60755ba
BLAKE2b-256 493ea632e44aed6f1c0e94e146ee7ded90b34b26951c26271898483d53a71f75

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2467c10e640b9f0a745110d14672b2996062ea697d219c79f3c08e9b11d95338
MD5 e2407ceb76fcd68bffff09a3395c2f2c
BLAKE2b-256 60cce1c7de32666019898f7cb09ab6cffeb8f88b175d5e4960acf31b98ca9e63

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 91cfd02df7048a99b60c66780252e81d78614e9049c950385048f98189c52f9f
MD5 7e2a110d21e21df9cc8a569e6d6c35a1
BLAKE2b-256 d80de5aa360d095f94f677ca66f6ea7def91f7cda76ecc93c18b0a7410874d67

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for lab_1806_vec_db-0.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 54f5c69b5893058cb9d3f9fe5eab45c186b715b4450d556c86b21d5ce8766092
MD5 fc90ab747f76fe1c7681301827dee6f1
BLAKE2b-256 28dd6bb520e1d971fb5911c04af743d25190c909ce1054d22bef566059d5dc3a

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