TiDB Vector Search and Ecto integration for Elixir applications.
TiDB provides tools and extensions for utilizing TiDB's native vector search
and advanced database features within Elixir and Ecto ecosystems.
Features
- Vector Struct & Serialization (
TiDB.Vector): A compact 32-bit floating point vector representation with conversions to/from Elixir lists, binaries, TiDB string literals, and optional Nx tensors. - Ecto Custom Type (
TiDB.Ecto.Vector): Seamlessly map TiDBVECTORcolumns to%TiDB.Vector{}structs in your Ecto schemas. - Vector Query Macros (
TiDB.Ecto.Vector.Query): Ecto query helper macros for TiDB vector distance functions including Cosine distance (vec_cosine_distance/2), L2/Euclidean distance (vec_l2_distance/2), L1/Manhattan distance (vec_l1_distance/2), negative inner product (vec_negative_inner_product/2), vector dimensions (vec_dims/1), and L2 norm (vec_l2_norm/1). - Migration Helpers (
TiDB.Ecto.Migrations): Migration macros to configure TiFlash replicas (enable_tiflash/2,disable_tiflash/1) and create Vector (vector_index/3) or Full-Text (fulltext_index/3) indexes with columnar replicas on demand. - Full-Text Search Macros (
TiDB.Ecto.Fulltext.Query): Query helpers for TiDB full-text search.
Quickstart
1. Define a Migration
defmodule MyApp.Repo.Migrations.CreateDocuments do
use Ecto.Migration
import TiDB.Ecto.Migrations
def change do
create table(:documents) do
add :title, :string
add :content, :text
add :embedding, :vector, size: 384
timestamps()
end
# Enable TiFlash replica and create an HNSW vector index
enable_tiflash("documents")
vector_index("documents", "embedding", distance: :cosine)
end
end2. Define an Ecto Schema
defmodule MyApp.Document do
use Ecto.Schema
import Ecto.Changeset
schema "documents" do
field :title, :string
field :content, :string
field :embedding, TiDB.Ecto.Vector
timestamps()
end
def changeset(document, attrs) do
document
|> cast(attrs, [:title, :content, :embedding])
|> validate_required([:title, :content, :embedding])
end
end3. Insert Vector Data
Vectors can be supplied as a list of numbers, an %TiDB.Vector{} struct, or an Nx.Tensor:
# Using a list of numbers
%MyApp.Document{}
|> MyApp.Document.changeset(%{
title: "TiDB Vector Guide",
content: "Vector search in TiDB...",
embedding: [0.023, -0.125, 0.891]
})
|> MyApp.Repo.insert!()
# Using TiDB.Vector explicitly
vector = TiDB.Vector.new([0.023, -0.125, 0.891])
MyApp.Repo.insert!(%MyApp.Document{title: "Doc 2", embedding: vector})4. Query by Vector Similarity (k-NN / ANN)
import Ecto.Query
import TiDB.Ecto.Vector.Query
query_vector = TiDB.Vector.new([0.025, -0.120, 0.880])
# Find the 5 most similar documents using Cosine Distance
results =
from(d in MyApp.Document,
select: %{
id: d.id,
title: d.title,
distance: vec_cosine_distance(d.embedding, ^query_vector)
},
order_by: [asc: vec_cosine_distance(d.embedding, ^query_vector)],
limit: 5
)
|> MyApp.Repo.all()