Why vector databases matter for developers
Vector databases power semantic search, recommendations, and retrieval-augmented pipelines by storing dense numeric embeddings and performing nearest-neighbor searches. This guide compares three popular options (Pinecone, Chroma, Weaviate) and gives practical PHP examples for embeddings, upserts, and queries. The goal is actionable guidance you can reuse long after the news cycle.
When to use a vector database
- Semantic search over documents, code, or conversations
- Hybrid search that mixes keyword matches and vector rank
- Personalized recommendations using user/item embeddings
- Retrieval for RAG-style LLM applications
High-level comparison
- Pinecone — managed, low-latency, production-ready SaaS. Good if you want a hosted service with scale and few operational responsibilities.
- Chroma — lightweight, embeddable, open-source. Good for local development, prototypes, and simple self-hosted needs.
- Weaviate — feature-rich, schema-driven, supports GraphQL and built-in vector transforms. Good when you need semantic filters, modular extensions, and self-hosted or cloud options.
Quick-start recipe (architecture)
- Generate text embeddings (use your embedding model of choice).
- Design a storage schema: id, vector, metadata (e.g., title, source, timestamp).
- Batch upsert vectors to your vector DB; include metadata for filterable queries.
- Perform nearest-neighbor queries with optional metadata filters and re-ranking.
- Combine vector scores with keyword scores for hybrid results if needed.
Actionable PHP examples
Below are minimal, safe-to-read PHP examples demonstrating: 1) calling an embeddings endpoint, 2) upserting to Pinecone, 3) querying Pinecone, and 4) inserting and querying in Weaviate. Replace placeholders (API keys, endpoints) with your values.
1) Create an embedding (OpenAI-style REST API)
<?php
$openaiKey = getenv('OPENAI_API_KEY');
$text = "San Francisco developer notes about vector databases";
$payload = json_encode(["model" => "text-embedding-3-small", "input" => $text]);
$ch = curl_init('https://api.openai.com/v1/embeddings');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $openaiKey,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
$vector = $result['data'][0]['embedding'] ?? null;
if (!$vector) {
throw new \Exception('Failed to get embedding');
}
// $vector is a numeric array you can upsert into your vector DB
print_r(array_slice($vector, 0, 5)); // preview
?>2) Upsert a vector to Pinecone
Use your Pinecone index endpoint and API key. Upsert in batches for throughput.
<?php
$pineconeApiKey = getenv('PINECONE_API_KEY');
$pineconeEndpoint = getenv('PINECONE_ENDPOINT'); // e.g. https://example-namespace.svc.pinecone.io
$indexName = 'my-index';
$id = 'doc-123';
$metadata = ['title' => 'Vector DB notes', 'source' => 'internal'];
$vectorPayload = [
'vectors' => [
[
'id' => $id,
'values' => $vector,
'metadata' => $metadata
]
]
];
$ch = curl_init("{$pineconeEndpoint}/vectors/upsert");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Api-Key: ' . $pineconeApiKey,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($vectorPayload));
$response = curl_exec($ch);
curl_close($ch);
$resp = json_decode($response, true);
if (empty($resp)) {
throw new \Exception('Pinecone upsert failed');
}
echo "Upserted vector: {$id}\n";
?>3) Query Pinecone (nearest neighbors + metadata filter)
<?php
$queryVector = $vector; // reuse embedding
$topK = 5;
$filter = ['source' => ['$eq' => 'internal']];
$payload = json_encode([
'vector' => $queryVector,
'topK' => $topK,
'includeMetadata' => true,
'filter' => $filter
]);
$ch = curl_init("{$pineconeEndpoint}/query");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Api-Key: ' . $pineconeApiKey,
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
$response = curl_exec($ch);
curl_close($ch);
$results = json_decode($response, true);
print_r($results['matches'] ?? []);
?>4) Insert and query with Weaviate (GraphQL) via REST
Weaviate exposes a REST and GraphQL API. The example below shows creating an object with an explicit vector and a GraphQL nearVector query.
<?php
$weaviateUrl = getenv('WEAVIATE_URL'); // e.g. https://weaviate.example.com
$weaviateKey = getenv('WEAVIATE_API_KEY');
// Create object
$object = [
'class' => 'Document',
'id' => 'doc-123',
'properties' => [
'title' => 'Vector DB notes',
'text' => 'Notes about Pinecone vs Weaviate'
],
'vector' => $vector
];
$ch = curl_init("{$weaviateUrl}/v1/objects");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $weaviateKey
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($object));
$response = curl_exec($ch);
curl_close($ch);
// Query via GraphQL: nearVector
$graphql = [
'query' => '{Get{Document(nearVector:{vector: [' . implode(',', array_map('floatval', array_slice($vector,0,10))) . '],certainty:0.7}){title,_additional{distance}}}}'
];
$ch = curl_init("{$weaviateUrl}/v1/graphql");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $weaviateKey
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($graphql));
$response = curl_exec($ch);
curl_close($ch);
$graphqlResp = json_decode($response, true);
print_r($graphqlResp);
?>Practical tips and tradeoffs
- Hosted vs self-hosted: Pinecone minimizes ops work and offers predictable SLAs. Chroma and Weaviate are strong if you need control or lower-cost self-hosting. Consider network latency and security boundaries.
- Indexing strategy: batch upserts to amortize overhead. For large datasets, shard or partition by logical key (tenant, region) to reduce query fanout.
- Metadata filtering: store structured metadata to apply fast pre-filters; reduces candidate set before expensive vector comparisons.
- Dimensionality and model choice: fewer dims → faster queries but potential quality loss. Normalize vectors and test models for your domain.
- Hybrid search: combine lexical search (BM25) with vector ranking for better precision on short queries or named entities.
- Cost tradeoffs: hosted services bill for storage, queries, and throughput. Self-hosting reduces direct cost but adds maintenance and scaling complexity.
- Consistency & freshness: consider write visibility and eventual consistency for use cases that need immediate reads after writes; test your DB's guarantees.
Operational checklist
- Monitor latency, throughput, and vector cardinality.
- Track embedding model version with each stored vector for safe reindexing later.
- Set up automated re-index or migration scripts when you change embedding models.
- Use schema versioning for metadata to support backward-compatible queries.
- Run offline recall/precision tests to validate retrieval quality after changes.
Further reading
The original comparison that inspired this practical guide is available here: Vector Databases Explained: Pinecone, Chroma, and Weaviate.
Conclusion
Vector databases are central to modern semantic applications. Choose Pinecone for a managed, production-ready experience, Chroma for embedded/local workflows, and Weaviate when you want schema-driven features and GraphQL support. Use embeddings consistently, batch upserts, store rich metadata for filtering, and combine vectors with lexical search when precision matters. The PHP examples above show simple, practical patterns you can adapt to your tech stack.
Next steps
- Run the embedding + upsert flow on a small subset of your data and evaluate recall.
- Experiment with hybrid ranking and metadata filters to reduce false positives.
- Build a monitoring dashboard to track retrieval quality and latency.
Was this helpful?
Share this post
Comments (0)
Want to join the conversation?
Log in or sign up to leave a comment and share your thoughts.
Log in to Comment