Download notebook · View source · Open in Colab
Work with Descriptors (Embeddings)
ApertureDB supports mulitmodal vector indexing, search, and classification so we could search for matching recipes or matching images of food dishes.
Connect to ApertureDB
Option A: ApertureDB Cloud (recommended)
Sign up for a free 30-day trial. Get your key from Connect > Generate API Key, add it to a .env file in this directory:
APERTUREDB_KEY=your_key_here
Option B: Community Edition (local Docker)
Run this in a terminal before starting the notebook:
docker run -d --name aperturedb \
-p 55555:55555 -e ADB_MASTER_KEY=admin -e ADB_FORCE_SSL=false \
aperturedata/aperturedb-community
%pip install --upgrade --quiet aperturedb python-dotenv
# Option A: ApertureDB Cloud
from dotenv import load_dotenv
load_dotenv() # loads APERTUREDB_KEY from .env into the environment
True
# Option B: Community Edition (local Docker)
# !adb config create localdb --active \
# --host localhost --port 55555 \
# --username admin --password admin \
# --no-use-ssl --no-interactive
from aperturedb.CommonLibrary import create_connector
client = create_connector()
response, _ = client.query([{"GetStatus": {}}])
client.print_last_response()
[
{
"GetStatus": {
"info": "OK",
"status": 0,
"system": "ApertureDB",
"version": "0.19.6"
}
}
]
Define the search space for recipes
This defines the search space to find similar descriptors(emmbeddings) to the given input Embedding
descriptorset_name = "recipe_search"
q = [{
"AddDescriptorSet": { # a new descriptor set / collection is added only if the name doesn't exist
"name": descriptorset_name,
"dimensions": 1024,
"engine": "Flat", # It's possible to choose different engines or even multiple
"metric": "L2", # It's possible to choose different distance metrics or even multiple
"properties": {
"year_created": 2023,
"source": "ApertureDB cookbook dataset",
"model": "embed-english-v3.0",
"provider": "cohere"
}
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"AddDescriptorSet": {
"status": 0
}
}
]
Prepare the embedding to be added
Embeddings, if precomputed, can come from a numpy file OR can be generated by calling a relevant embedding model.
import numpy as np
# Download the sample file
! mkdir -p data; cd data; wget https://github.com/aperture-data/Cookbook/blob/e333f6c59070b9165033d9ddd5af852a6b9624ba/notebooks/simple/data/embeddings.npy; cd -
# File can contain multiple descriptors of matching dimensions. So you can load them
# by passing the right index
embedding_npy_array = np.load("data/embeddings.npy")
index = 0 # We currently have only one embedding in the file
embedding = embedding_npy_array[index]
# expected byte array format for adding descriptor in ApertureDB
embedding_bytes = embedding.astype('float32').tobytes()
--2026-04-03 07:36:46-- https://github.com/aperture-data/Cookbook/blob/e333f6c59070b9165033d9ddd5af852a6b9624ba/notebooks/simple/data/embeddings.npy
Resolving github.com (github.com)... 140.82.116.4
Connecting to github.com (github.com)|140.82.116.4|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘embeddings.npy.1’
embeddings.npy.1 [ <=> ] 220.55K --.-KB/s in 0.03s
2026-04-03 07:36:49 (6.73 MB/s) - ‘embeddings.npy.1’ saved [225840]
/mnt/persistent/notebooks/Cookbook/notebooks/simple
Add a Recipe Embedding for Similarity Search Later
For bulk additions, we recommend using the Python SDK loaders
q = [{
"AddDescriptor": {
"set": descriptorset_name, # descriptors / embeddings are always added to a set / collection
"label": "dinner",
"properties": {
"id": 75,
"year_created": 2023,
"source": "Cookbook recipe",
"model": "embed-english-v3.0",
"provider": "cohere"
},
"if_not_found": { # conditional add
"id": ["==", 75]
}
}
}]
responses, blobs = client.query(q, [embedding_bytes])
print(client.get_last_response_str())
[
{
"AddDescriptor": {
"status": 0
}
}
]
K-NN Search For Matching Embedding
Since we have only added one and we are searching that same one, we expect one matching embedding
q = [{
"FindDescriptor": {
# Specify the descriptor set in which to search.
"set": descriptorset_name,
"k_neighbors": 6,
"distances": True,
"labels": True,
"blobs": True,
"results": {
"all_properties": True
}
}
}]
responses, blobs = client.query(q, [embedding_bytes])
print(client.get_last_response_str())
[
{
"FindDescriptor": {
"blobs_start": 0,
"entities": [
{
"_blob_index": 0,
"_distance": 0.0,
"_label": "dinner",
"_set_name": "recipe_search",
"_uniqueid": "3.192.487880",
"id": 75,
"model": "embed-english-v3.0",
"provider": "cohere",
"source": "Cookbook recipe",
"year_created": 2023
}
],
"returned": 1,
"status": 0
}
}
]
Remove Extra Properties with Update
q = [{
"UpdateDescriptor": {
"constraints": {
"id": ["==", 75]
},
"remove_props": ["year_created"]
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"UpdateDescriptor": {
"count": 1,
"status": 0
}
}
]
Double Check if Update Worked
q = [{
"FindDescriptor": {
# Specify the descriptor set in which to search.
"set": descriptorset_name,
"constraints": {
"id": ["==", 75]
},
"results": {
"all_properties": True
}
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"FindDescriptor": {
"entities": [
{
"_set_name": "recipe_search",
"_uniqueid": "3.192.487880",
"id": 75,
"model": "embed-english-v3.0",
"provider": "cohere",
"source": "Cookbook recipe"
}
],
"returned": 1,
"status": 0
}
}
]
Remove the Embedding
q = [{
"DeleteDescriptor": {
"constraints": {
"provider": ["==", "cohere"]
}
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"DeleteDescriptor": {
"count": 1,
"status": 0
}
}
]
Verify Deletion
q = [{
"FindDescriptor": {
# Specify the descriptor set in which to search.
"set": descriptorset_name,
"constraints": {
"id": ["==", 75]
},
"results": {
"all_properties": True
}
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"FindDescriptor": {
"returned": 0,
"status": 0
}
}
]
Remove the Descriptor Set
q = [{
"DeleteDescriptorSet": {
"with_name": descriptorset_name
}
}]
responses, blobs = client.query(q)
print(client.get_last_response_str())
[
{
"DeleteDescriptorSet": {
"count": 1,
"status": 0
}
}
]
What's next?