API Cheatsheet
Quick reference for the most important Vectra APIs.
For full details, see the API Overview and provider guides.
Core Client
Initialize Client
require 'vectra'
client = Vectra::Client.new(
provider: :qdrant, # :pinecone, :qdrant, :weaviate, :pgvector, :memory
api_key: ENV['QDRANT_API_KEY'],
host: 'http://localhost:6333',
environment: 'us-west-4' # For Pinecone
)
Or use shortcuts:
client = Vectra.qdrant(host: 'http://localhost:6333')
client = Vectra.pinecone(api_key: ENV['PINECONE_API_KEY'], environment: 'us-west-4')
client = Vectra.pgvector(connection_url: ENV['DATABASE_URL'])
client = Vectra.memory # In-memory (testing only)
You can also set a default index and namespace:
client = Vectra::Client.new(
provider: :qdrant,
host: 'http://localhost:6333',
index: 'products',
namespace: 'tenant-1'
)
# Now index and namespace can be omitted
client.upsert(vectors: [...])
client.query(vector: query_embedding, top_k: 10)
Upsert
client.upsert(
index: 'documents',
vectors: [
{
id: 'doc-1',
values: embedding_array,
metadata: { title: 'Hello World', category: 'docs' }
}
],
namespace: 'default' # optional
)
Query (similarity search)
results = client.query(
index: 'documents',
vector: query_embedding,
top_k: 10,
filter: { category: 'docs' },
namespace: 'default',
include_values: false,
include_metadata: true
)
results.each do |match|
puts "#{match.id} (score=#{match.score.round(3)}): #{match.metadata['title']}"
end
Hybrid Search (semantic + keyword)
results = client.hybrid_search(
index: 'documents',
vector: query_embedding,
text: 'ruby vector search',
alpha: 0.7, # 70% semantic, 30% keyword
top_k: 10,
filter: { category: 'blog' }
)
Supported providers: Qdrant ✅, Weaviate ✅, pgvector ✅, Pinecone ⚠️
Text Search (keyword-only, no embeddings)
results = client.text_search(
index: 'products',
text: 'iPhone 15 Pro',
top_k: 10,
filter: { category: 'electronics' }
)
results.each do |match|
puts "#{match.id} (score=#{match.score.round(3)}): #{match.metadata['title']}"
end
Supported providers: Qdrant ✅ (BM25), Weaviate ✅ (BM25), pgvector ✅ (PostgreSQL full-text)
Fetch
vectors = client.fetch(
index: 'documents',
ids: ['doc-1', 'doc-2'],
namespace: 'default'
)
vectors['doc-1'].values # => [0.1, 0.2, ...]
vectors['doc-1'].metadata # => { 'title' => 'Hello World' }
Update
client.update(
index: 'documents',
id: 'doc-1',
metadata: { category: 'guides' }
)
Delete
# By IDs
client.delete(index: 'documents', ids: ['doc-1', 'doc-2'])
# By filter
client.delete(index: 'documents', filter: { category: 'old' })
# Delete all in namespace
client.delete(index: 'documents', delete_all: true)
Index Management
# Create index
client.create_index(name: 'documents', dimension: 384, metric: 'cosine')
# List indexes
indexes = client.list_indexes
# => [{ name: 'documents', dimension: 384, ... }]
# Describe index
info = client.describe_index(index: 'documents')
# => { name: 'documents', dimension: 384, metric: 'cosine', status: 'ready' }
# Get stats
stats = client.stats(index: 'documents')
# => { total_vector_count: 1000, dimension: 384, namespaces: { ... } }
# List namespaces
namespaces = client.list_namespaces(index: 'documents')
# => ['tenant-1', 'tenant-2']
# Delete index
client.delete_index(name: 'old-index')
Note: create_index and delete_index are supported by Pinecone, Qdrant, and pgvector. Memory and Weaviate providers don’t support these operations.
Health & Monitoring
Health Check
if client.healthy?
puts 'Vectra provider is healthy'
else
puts 'Vectra provider is NOT healthy'
end
Ping (with latency)
status = client.ping
# => { healthy: true, provider: :qdrant, latency_ms: 23.4 }
puts "Provider: #{status[:provider]}, latency: #{status[:latency_ms]}ms"
Rails Health Endpoint (Example)
# config/routes.rb
Rails.application.routes.draw do
get '/health/vectra', to: 'health#vectra'
end
# app/controllers/health_controller.rb
class HealthController < ApplicationController
def vectra
client = Vectra::Client.new
status = client.ping
if status[:healthy]
render json: { status: 'ok', provider: status[:provider], latency_ms: status[:latency_ms] }
else
render json: { status: 'unhealthy' }, status: :service_unavailable
end
rescue => e
render json: { status: 'error', error: e.message }, status: :service_unavailable
end
end
Use this endpoint for Kubernetes / load balancer health checks.
Vector Helpers
Normalize Embeddings
embedding = openai_response['data'][0]['embedding']
normalized = Vectra::Vector.normalize(embedding, type: :l2) # or :l1
client.upsert(
index: 'documents',
vectors: [
{ id: 'doc-1', values: normalized, metadata: { title: 'Hello' } }
]
)
In-Place Normalization
vector = Vectra::Vector.new(id: 'doc-1', values: embedding)
vector.normalize! # Mutates values
client.upsert(index: 'documents', vectors: [vector])
Embedding Cache Helper
cache = Vectra::Cache.new(ttl: 600, max_size: 1000)
embedding = Vectra::Embeddings.fetch(
cache: cache,
model_name: "Product",
id: product.id,
input: product.description,
field: :description
) do
EmbeddingService.generate(product.description)
end
Batch Operations
Simple Batch Upsert
vectors = products.map do |product|
{
id: product.id.to_s,
values: product.embedding,
metadata: { name: product.name, price: product.price }
}
end
client.upsert(index: 'products', vectors: vectors)
Batch with Progress Callback
Vectra::Batch.upsert(
client: client,
index: 'products',
vectors: vectors,
batch_size: 100,
on_progress: ->(batch_index, total_batches, batch_count) do
puts "Batch #{batch_index + 1}/#{total_batches} (#{batch_count} vectors)"
end
)
Batch Query (Multiple Vectors)
batch = Vectra::Batch.new(client, concurrency: 4)
# Find similar items for multiple products at once
product_embeddings = products.map(&:embedding)
results = batch.query_async(
index: 'products',
vectors: product_embeddings,
top_k: 5
)
# Each result corresponds to one product
results.each_with_index do |result, i|
puts "Similar to product #{i}: #{result.ids}"
end
ActiveRecord + has_vector DSL
Basic Setup
class Document < ApplicationRecord
include Vectra::ActiveRecord
has_vector :embedding,
provider: :qdrant,
index: 'documents',
dimension: 1536,
metadata_fields: [:title, :category]
end
Auto-Index on Save
doc = Document.create!(
title: 'Hello World',
category: 'docs',
embedding: EmbeddingService.generate('Hello World')
)
Vector Search from Model
results = Document.vector_search(
embedding: EmbeddingService.generate('vector search in ruby'),
limit: 10,
filter: { category: 'docs' }
)
results.each do |doc|
puts doc.title
end
Reindex All Records
# Reindex all documents that already have embeddings
processed = Document.reindex_vectors(
scope: Document.where.not(embedding: nil),
batch_size: 500
)
puts "Reindexed #{processed} documents"
Error Handling
begin
client.query(index: 'missing', vector: [0.1, 0.2, 0.3])
rescue Vectra::NotFoundError => e
Rails.logger.warn("Index not found: #{e.message}")
rescue Vectra::RateLimitError => e
Rails.logger.error("Rate limited: #{e.message}")
rescue Vectra::Error => e
Rails.logger.error("Vectra error: #{e.message}")
end