Published on May 11, 2026
Go homeSemantic search in Sqlite
If you need a simple low infrastructure solution to semantic search in Django here is one possible solution.
This requires that embeddings are stored as numpy arrays in sqlite. You can model this using the BinaryField (Note you will also need to generate embeddings, that is out of scope of this post).
class Model(models.Model):
embedding = models.BinaryField(null=True, blank=True)
We then register the vector_distance_cos and vector_score_cos functions as custom functions.
import typing as t
import numpy as np
from django.apps import AppConfig
from django.db.backends.signals import connection_created
def vector_distance_cos(a: bytes, b: bytes) -> float:
"""Returns the cosine similarity between 2 vectors.
The cosine similarity always belongs to the interval [−1, +1].
- Two proportional vectors have a cosine similarity of +1
- Two orthogonal vectors have a similarity of 0
- Two opposite vectors have a similarity of −1
"""
a_array = np.frombuffer(a, dtype=np.float64)
b_array = np.frombuffer(b, dtype=np.float64)
return float(a_array @ b_array / (np.linalg.norm(a_array) * np.linalg.norm(b_array)))
def vector_score_cos(a: bytes, b: bytes) -> float:
"""Returns a normalized score for cosine similarity between 0 and 1."""
return (vector_distance_cos(a, b) + 1) / 2
def on_connection_created(sender: t.Any, connection: t.Any, **kwargs: t.Any) -> None:
"""Runs each time Django creates a DB connection."""
if connection.vendor != "sqlite":
return
connection.connection.create_function("vector_distance_cos", 2, vector_distance_cos)
connection.connection.create_function("vector_score_cos", 2, vector_score_cos)
class DbConfig(AppConfig):
"""Config for the database application."""
name = "db"
verbose_name = "Database"
def ready(self) -> None:
connection_created.connect(on_connection_created)
The vector_distance_cos and vector_score_cos functions will now be available to us in SQL.
SELECT
vector_score_cos(embedding, :embedding) score
FROM table
ORDER BY
score DESC
LIMIT 10