.cursor/skills/elixir-vector-patterns/SKILL.md
Elixir patterns for vector storage and similarity search. Use when implementing GenServer-based vector store, ETS index, Nx/Scholar distance math, or supervision for a vector DB in Elixir.
npx skillsauth add 8dazo/elix-db elixir-vector-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use a GenServer to own an ETS table keyed by id; store {id, vector, metadata}. Vectors as list or Nx tensor (serialize to binary for ETS if needed).
defmodule ElixDb.VectorStore do
use GenServer
def start_link(opts) do
name = Keyword.fetch!(opts, :name)
dimension = Keyword.fetch!(opts, :dimension)
GenServer.start_link(__MODULE__, {name, dimension}, name: name)
end
def init({name, dimension}) do
table = :ets.new(name, [:set, :protected, :named_table])
{:ok, %{table: table, dimension: dimension}}
end
def insert(server, id, vector, metadata \\ %{}) do
GenServer.call(server, {:insert, id, vector, metadata})
end
def search(server, query_vector, k \\ 10) do
GenServer.call(server, {:search, query_vector, k})
end
def handle_call({:insert, id, vector, metadata}, _from, state) do
:ets.insert(state.table, {id, vector, metadata})
{:reply, :ok, state}
end
def handle_call({:search, query_vector, k}, _from, state) do
results = do_knn(state.table, query_vector, k)
{:reply, results, state}
end
defp do_knn(table, query_vector, k) do
# Collect all, compute distances, sort, take k (see distance section)
:ets.tab2list(table)
|> Enum.map(fn {id, vec, meta} -> {id, cosine_similarity(query_vector, vec), meta} end)
|> Enum.sort_by(fn {_id, sim, _} -> -sim end, :asc)
|> Enum.take(k)
end
end
Cosine similarity (for normalized vectors, dot product = cosine):
# Nx: ensure vectors are 1-D tensors
def cosine_similarity(a, b) do
a = Nx.tensor(a)
b = Nx.tensor(b)
Nx.divide(Nx.dot(a, b), Nx.multiply(Nx.Linalg.norm(a), Nx.Linalg.norm(b)))
|> Nx.squeeze()
|> Nx.to_number()
end
Scholar (pairwise cosine distance = 1 - similarity):
# Scholar.Metrics.Distance.cosine/3 returns distance; similarity = 1 - distance
# pairwise_cosine for many vectors at once (batch)
L2 (Euclidean) distance:
def l2_distance(a, b) do
a = Nx.tensor(a)
b = Nx.tensor(b)
Nx.Linalg.norm(Nx.subtract(a, b)) |> Nx.squeeze() |> Nx.to_number()
end
Use one metric consistently for insert and search.
[0.1, -0.2, ...]Nx.to_flat_list(vec) |> :erlang.list_to_binary() and decode when reading (saves memory for large tables)Run the vector store under your application so it survives restarts and is started in order.
# lib/elix_db/application.ex
children = [
{ElixDb.VectorStore, name: ElixDb.VectorStore, dimension: 1536}
]
Supervisor.start_link(children, strategy: :one_for_one)
:protected ETS so other processes can read (e.g. :ets.lookup) while GenServer handles writes if you split read path later.business
When publishing a new elix-db version or making version changes, run versioned sample use cases, collect memory/time/latency, compare to the previous version report, and update reports. Remember this workflow for releases.
development
Storage backends and indexing for vector databases in Elixir. Use when choosing persistence, implementing exact vs approximate k-NN, or integrating pgvector, file, or ETS for vector storage.
development
Design and implement a vector database in Elixir. Use when building embedding storage, similarity search, k-NN retrieval, or when the user mentions vector DB, embeddings, or semantic search in Elixir.
development
Debug, verify, and compare elix-db to industry after each plan step. Use after implementing any plan step or changing vector/store/API logic; run tests, IEx checks, and document efficiency vs Qdrant/Milvus/pgvector.