Posted on
Artificial Intelligence

Vector Databases for Artificial Intelligence

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Vector Databases for Artificial Intelligence: A Bash-first Guide on Linux

AI apps don’t just need data—they need memory. When you’re matching a user’s question to the most relevant document, comparing images, or deduplicating content, you’re comparing high‑dimensional vectors (embeddings), not plain text. Grep won’t help you here. Vector databases are purpose-built to store, index, and search embeddings at scale—in milliseconds.

This post shows you why vector databases matter, when to use them, and how to stand up three proven options from your Linux terminal. All commands include apt, dnf, and zypper variants for a smooth start on Debian/Ubuntu, Fedora/RHEL, and openSUSE.


Why vector databases?

  • Similarity search at scale: Find the “nearest neighbors” to a query vector among millions of embeddings fast (often using approximate nearest neighbor, ANN, indexes like IVF/HNSW).

  • Tailored distance metrics: Cosine, dot product, L2—choose what matches your model and task.

  • Metadata filters: Search vectors with structured filters (e.g., by tenant, timestamp, tags).

  • Production features: Persistence, replication (where supported), schema management, and integrations—beyond what ad hoc FAISS files or in-memory arrays provide.

Common use cases:

  • RAG (Retrieval Augmented Generation) for docs/code

  • Semantic search and recommendations

  • Image/audio similarity

  • Near-duplicate detection and clustering


Choose the right engine (quick decision points)

  • PostgreSQL + pgvector: Best when you already live in Postgres; strong relational + vector in one place; great for small-to-mid scale and transactional + semantic blends.

  • Qdrant: Purpose-built vector DB with a clean HTTP API and filters; fast to run in a single container.

  • Weaviate: Vector DB with a schema and GraphQL/REST; can ingest with your own vectors or via modules; easy to prototype.

Below: quickstarts for each—pure Bash.


Prerequisites (tools we’ll use)

Install curl and jq:

  • apt:
sudo apt update
sudo apt install -y curl jq
  • dnf:
sudo dnf install -y curl jq
  • zypper:
sudo zypper install -y curl jq

We’ll also use Podman to run containers rootlessly (Docker works too):

  • apt:
sudo apt update
sudo apt install -y podman
  • dnf:
sudo dnf install -y podman
  • zypper:
sudo zypper install -y podman

Option 1: PostgreSQL + pgvector

Postgres gives you vectors where your relational data already lives. Great for hybrid queries (e.g., “top-10 semantically similar docs WHERE tenant_id=123 AND status='active'”).

1) Install PostgreSQL and build tools

  • apt (Debian/Ubuntu):
sudo apt update
sudo apt install -y postgresql postgresql-contrib postgresql-server-dev-all build-essential git
sudo systemctl enable --now postgresql
  • dnf (Fedora/RHEL/Alma/Rocky):
sudo dnf install -y postgresql-server postgresql-contrib postgresql-server-devel gcc make git
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
  • zypper (openSUSE/SLES):
sudo zypper install -y postgresql-server postgresql-contrib postgresql-devel gcc make git
sudo systemctl enable --now postgresql

2) Install pgvector from source (works across distros)

git clone https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install

3) Enable the extension and create a demo table

sudo -u postgres psql -d postgres -c "CREATE EXTENSION IF NOT EXISTS vector;"
sudo -u postgres psql -d postgres <<'SQL'
DROP TABLE IF EXISTS items;
CREATE TABLE items (
  id bigserial PRIMARY KEY,
  embedding vector(3),
  data text
);

-- Insert some toy 3D vectors
INSERT INTO items (embedding, data) VALUES
  ('[0.1, 0.2, 0.3]', 'alpha'),
  ('[0.9, 0.1, 0.2]', 'beta'),
  ('[0.05, 0.2, 0.1]', 'gamma'),
  ('[0.2, 0.1, 0.9]', 'delta');

-- Choose a distance; here we’ll build an IVF index for L2
CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
ANALYZE items;

-- Query by vector: smaller distance is better for L2
SELECT id, data, (embedding <-> '[0.1,0.2,0.25]') AS distance
FROM items
ORDER BY embedding <-> '[0.1,0.2,0.25]'
LIMIT 3;
SQL

Notes:

  • Choose dimension to match your embedding model (e.g., 384, 768, 1024, 1536).

  • For cosine similarity: store normalized vectors or use vector_cosine_ops.

  • For approximate search: adjust lists (index) and ivfflat.probes (session) for speed/recall tradeoffs.


Option 2: Qdrant (HTTP-first, fast, simple)

Qdrant is a dedicated vector database with an ergonomic REST API and strong filtering.

1) Run Qdrant via Podman

podman run -d --name qdrant \
  -p 6333:6333 \
  -v qdrant_storage:/qdrant/storage \
  docker.io/qdrant/qdrant:latest

2) Create a collection (3D vectors; cosine distance)

curl -s -X PUT "http://localhost:6333/collections/demo" \
  -H "Content-Type: application/json" \
  -d '{
    "vectors": { "size": 3, "distance": "Cosine" }
  }' | jq

3) Upsert points with payloads

curl -s -X PUT "http://localhost:6333/collections/demo/points" \
  -H "Content-Type: application/json" \
  -d '{
    "points": [
      {"id": 1, "vector": [0.1,0.2,0.3], "payload": {"doc": "alpha", "tenant": 1}},
      {"id": 2, "vector": [0.9,0.1,0.2], "payload": {"doc": "beta",  "tenant": 1}},
      {"id": 3, "vector": [0.05,0.2,0.1],"payload": {"doc": "gamma", "tenant": 2}},
      {"id": 4, "vector": [0.2,0.1,0.9], "payload": {"doc": "delta", "tenant": 2}}
    ]
  }' | jq

4) Search with a filter

curl -s -X POST "http://localhost:6333/collections/demo/points/search" \
  -H "Content-Type: application/json" \
  -d '{
    "vector": [0.1,0.2,0.25],
    "limit": 3,
    "with_payload": true,
    "filter": {"must": [{"key": "tenant", "match": {"value": 1}}]}
  }' | jq

Tip: For production, tune HNSW parameters (m, ef_construct, ef) and quantization/compression as needed.


Option 3: Weaviate (schema + GraphQL/REST)

Weaviate adds a flexible schema and GraphQL interface. You can use external vectorizers or push your own vectors.

1) Run Weaviate via Podman

podman run -d --name weaviate \
  -p 8080:8080 \
  -e QUERY_DEFAULTS_LIMIT=25 \
  -e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
  -e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
  -v weaviate_data:/var/lib/weaviate \
  docker.io/semitechnologies/weaviate:latest

2) Create a class (no built-in vectorizer; we’ll supply vectors)

curl -s -X POST "http://localhost:8080/v1/schema" \
  -H "Content-Type: application/json" \
  -d '{
    "classes": [{
      "class": "Doc",
      "vectorizer": "none",
      "properties": [{"name": "text", "dataType": ["text"]}]
    }]
  }' | jq

3) Insert objects with custom vectors

curl -s -X POST "http://localhost:8080/v1/objects" \
  -H "Content-Type: application/json" \
  -d '{"class":"Doc","properties":{"text":"alpha"},"vector":[0.1,0.2,0.3]}' | jq

curl -s -X POST "http://localhost:8080/v1/objects" \
  -H "Content-Type: application/json" \
  -d '{"class":"Doc","properties":{"text":"beta"},"vector":[0.9,0.1,0.2]}' | jq

4) GraphQL query by vector

curl -s "http://localhost:8080/v1/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ Get { Doc(nearVector:{vector:[0.1,0.2,0.25]}, limit:3) { text _additional { distance } } } }"}' | jq

Tip: If you prefer integrated embeddings, enable and configure a vectorizer module (e.g., text2vec-*), or route embedding generation through your app and pass vectors explicitly as above.


Real-world tips for better results

  • Pick the right metric:

    • Cosine: scale-invariant semantic similarity (common default for text embeddings).
    • Dot product: ranking focus when vectors are not normalized.
    • L2: useful in many numeric spaces and when models are tuned for Euclidean distance.
  • Normalize vectors consistently when using cosine:

norm_vec() { # usage: norm_vec "0.1 0.2 0.3"
  read -ra a <<<"$1"; s=0; for x in "${a[@]}"; do s=$(awk -v s="$s" -v x="$x" 'BEGIN{print s + x*x}'); done
  mag=$(awk -v s="$s" 'BEGIN{print sqrt(s)}')
  out=(); for x in "${a[@]}"; do out+=($(awk -v x="$x" -v m="$mag" 'BEGIN{print x/m}')); done
  printf '%s\n' "${out[*]}"
}
  • Index tuning matters:

    • pgvector IVF: increase lists (index build) and ivfflat.probes (query) for recall; trade for latency.
    • Qdrant HNSW: tune ef (query-time) and ef_construct/m (build-time).
  • Store metadata:

    • Keep tenant, timestamps, tags alongside vectors for filtered search.
  • Batch inserts:

    • Use bulk endpoints/transactions to minimize index rebuild overhead.

Conclusion and next steps

Vector databases turn embeddings into a live, searchable memory for your AI systems. Start where you are:

  • Already on Postgres? Enable pgvector and ship.

  • Need a lean, HTTP-first engine? Spin up Qdrant.

  • Prefer schema + GraphQL? Try Weaviate.

Your next step:

  • Stand up one of the quickstarts above on your distro.

  • Swap the toy 3D vectors for real embeddings from your model.

  • Add filters and tune index parameters to hit your latency/recall goals.

Have a favorite workflow or a gotcha worth sharing? Drop it in your team docs or open a gist—your future self (and your users) will thank you.