pgvector SQL Support GuideΒΆ
BenoStreamDB pgvector-Compatible SQL Interface
BenoStreamDB provides full pgvector-compatible SQL syntax through Apache DataFusion integration, allowing you to use familiar PostgreSQL vector operations for similarity search, aggregations, and type conversions.
Table of ContentsΒΆ
Distance OperatorsΒΆ
BenoStreamDB supports all six pgvector distance operators for computing vector similarity:
Operator |
Distance Metric |
Description |
BenoStreamDB Type |
Upstream pgvector Type |
Use Case |
|---|---|---|---|---|---|
|
L2 (Euclidean) |
Straight-line distance |
|
|
General similarity |
|
Cosine |
Angle-based similarity |
|
|
Text embeddings |
|
Inner Product |
Negative dot product |
|
|
Recommendation systems |
|
L1 (Manhattan) |
Sum of absolute differences |
|
|
Sparse data |
|
Hamming |
Bit difference count |
|
|
Binary vectors / bitsets |
|
Jaccard |
Set similarity |
|
|
Categorical / indicator sets |
Note on
<~>and<%>: In upstream PostgreSQLpgvector,<~>and<%>only accept the native PostgreSQLbittype (e.g.'101'::bit(3)). In BenoStreamDB, these operators are extended to execute directly on standard::vector(Arrow Float32) columns without requiring casting or binary conversion functions. See Compatibility Notes & Conversions below for exact PostgreSQL translation syntax.
Basic UsageΒΆ
-- L2 distance (Euclidean)
SELECT id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
WHERE embedding <-> '[0.1, 0.2, 0.3]'::vector < 0.5;
-- Cosine distance
SELECT id, embedding <=> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance LIMIT 10;
-- Inner product
SELECT id, embedding <#> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents;
Operator EquivalenceΒΆ
Distance operators are equivalent to their corresponding UDF functions:
-- These are equivalent:
SELECT embedding <-> query_vec FROM table;
SELECT dist_l2(embedding, query_vec) FROM table;
-- These are equivalent:
SELECT embedding <=> query_vec FROM table;
SELECT dist_cosine(embedding, query_vec) FROM table;
Vector LiteralsΒΆ
Vector literals allow you to specify vectors directly in SQL queries without parameter binding.
Dense VectorsΒΆ
-- Basic syntax
'[1, 2, 3]'::vector
-- With floating-point values
'[0.1, 0.2, 0.3]'::vector
-- With dimension specification
'[1, 2, 3]'::vector(3)
-- In queries
SELECT * FROM documents
WHERE embedding <-> '[0.1, 0.2, 0.3]'::vector < 0.5;
Sparse VectorsΒΆ
-- Sparse vector literal (index:value pairs)
'{1:0.5, 10:0.3, 100:0.8}'::sparsevec(1000)
-- In queries
SELECT id, sparse_embedding <-> '{1:0.5, 10:0.3}'::sparsevec(1000) AS distance
FROM documents
ORDER BY distance LIMIT 10;
Binary VectorsΒΆ
-- Binary literal (bit string)
B'10110101'
-- Hexadecimal format
'\\xB5'::bit(8)
-- In queries
SELECT id, binary_embedding <~> B'10110101' AS distance
FROM documents;
KNN QueriesΒΆ
K-Nearest Neighbors (KNN) queries find the k most similar vectors to a query vector. BenoStreamDB automatically optimizes these queries to use vector indexes.
Basic KNNΒΆ
-- Find 10 nearest neighbors
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
KNN with FiltersΒΆ
Combine vector search with scalar filters for hybrid queries:
-- Find nearest neighbors in a specific category
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
WHERE category = 'science'
ORDER BY distance
LIMIT 10;
-- Multiple filters
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
WHERE category = 'science'
AND published_date > '2024-01-01'
AND author_id IN (1, 2, 3)
ORDER BY distance
LIMIT 10;
KNN with PaginationΒΆ
-- First page (results 1-10)
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
-- Second page (results 11-20)
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10 OFFSET 10;
Distance Threshold QueriesΒΆ
-- Find all vectors within distance threshold
SELECT id, content, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
WHERE embedding <-> '[0.1, 0.2, 0.3]'::vector < 0.5
ORDER BY distance;
Configuration ParametersΒΆ
Control vector search behavior per query with the INDEX_HINT optimizer hint.
HNSW ParametersΒΆ
-- ef_search controls the search beam width (default: 64)
-- Higher values = more accurate but slower
SELECT /*+ INDEX_HINT(ef_search=128) */
id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
IVF ParametersΒΆ
-- probes controls how many IVF clusters are scanned (default: 10)
-- Higher values = more accurate but slower
SELECT /*+ INDEX_HINT(probes=20) */
id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
Index ControlΒΆ
-- Force index usage (default: true)
SELECT /*+ INDEX_HINT(use_index=true) */
id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
-- Disable index for testing (forces sequential scan)
SELECT /*+ INDEX_HINT(use_index=false) */
id, embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
Python APIΒΆ
import benostreamdb as bsdb
table = bsdb.Table("s3://bucket/documents")
# Pass index-tuning parameters alongside the vector filter
results = table.to_pandas(
vector_filter={
"column": "embedding",
"query": [0.1, 0.2, 0.3],
"k": 10,
"ef_search": 128,
"probes": 20,
}
)
Sparse VectorsΒΆ
Sparse vectors efficiently represent high-dimensional vectors with mostly zero values.
Creating Sparse Vector TablesΒΆ
CREATE TABLE documents (
id INTEGER,
content TEXT,
sparse_embedding sparsevec(10000)
);
Sparse Vector OperationsΒΆ
-- Insert sparse vectors
INSERT INTO documents (id, content, sparse_embedding)
VALUES (1, 'document text', '{1:0.5, 100:0.3, 500:0.8}'::sparsevec(10000));
-- Query sparse vectors
SELECT id, sparse_embedding <-> '{1:0.5, 10:0.3}'::sparsevec(10000) AS distance
FROM documents
ORDER BY distance
LIMIT 10;
-- Get sparse vector dimensions
SELECT id, sparsevec_dims(sparse_embedding) AS dimensions
FROM documents;
-- Get non-zero count
SELECT id, sparsevec_nnz(sparse_embedding) AS non_zero_count
FROM documents;
Sparse Vector Utility FunctionsΒΆ
-- Get dimensionality
SELECT sparsevec_dims('{1:0.5, 10:0.3}'::sparsevec(1000));
-- Returns: 1000
-- Get non-zero element count
SELECT sparsevec_nnz('{1:0.5, 10:0.3}'::sparsevec(1000));
-- Returns: 2
Binary VectorsΒΆ
Binary vectors use bit-packed representation for memory-efficient storage and fast Hamming distance computation.
Binary QuantizationΒΆ
-- Convert dense vector to binary
SELECT binary_quantize('[0.1, -0.2, 0.3, -0.4]'::vector) AS binary_vec;
-- Returns: B'1010' (1 if >= 0, 0 if < 0)
-- Store binary vectors
CREATE TABLE documents (
id INTEGER,
content TEXT,
binary_embedding bit(1024)
);
Binary Vector OperationsΒΆ
-- Hamming distance on binary vectors
SELECT id, binary_embedding <~> B'10110101' AS distance
FROM documents
ORDER BY distance
LIMIT 10;
-- Binary vector literals
SELECT id, binary_embedding <~> '\\xB5'::bit(8) AS distance
FROM documents;
Binary Vector DisplayΒΆ
-- Format binary vector for display
SELECT id, format_binary_vector(binary_embedding, 8) AS binary_str
FROM documents;
-- Returns: "10110101" or "0xB5"
Vector AggregationsΒΆ
Compute aggregate statistics over vector columns.
Vector SumΒΆ
-- Sum all vectors in a table
SELECT vector_sum(embedding) AS total
FROM documents;
-- Sum vectors by group
SELECT category, vector_sum(embedding) AS category_sum
FROM documents
GROUP BY category;
Vector Average (Centroid)ΒΆ
-- Compute centroid of all vectors
SELECT vector_avg(embedding) AS centroid
FROM documents;
-- Compute centroid per category
SELECT category, vector_avg(embedding) AS centroid
FROM documents
GROUP BY category;
-- Find documents closest to category centroid
WITH centroids AS (
SELECT category, vector_avg(embedding) AS centroid
FROM documents
GROUP BY category
)
SELECT d.id, d.content, d.embedding <-> c.centroid AS distance
FROM documents d
JOIN centroids c ON d.category = c.category
ORDER BY distance
LIMIT 10;
Aggregation with FiltersΒΆ
-- Aggregate filtered results
SELECT category, vector_avg(embedding) AS centroid
FROM documents
WHERE published_date > '2024-01-01'
GROUP BY category
HAVING COUNT(*) > 10;
Type CastingΒΆ
Convert between different vector representations.
Dense to SparseΒΆ
-- Cast dense vector to sparse (filters out zeros)
SELECT '[0.1, 0, 0.3, 0, 0.5]'::vector::sparsevec AS sparse_vec;
-- Returns: {0:0.1, 2:0.3, 4:0.5}
Sparse to DenseΒΆ
-- Cast sparse vector to dense (expands with zeros)
SELECT '{1:0.5, 10:0.3}'::sparsevec(100)::vector AS dense_vec;
-- Returns: [0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0.3, 0, ...]
Vector to BinaryΒΆ
-- Cast vector to binary (binary quantization)
SELECT '[0.1, -0.2, 0.3, -0.4]'::vector::bit AS binary_vec;
-- Returns: B'1010'
Float Precision ConversionΒΆ
-- Cast Float32 to Float16 (reduces precision)
SELECT '[0.123456789, 0.987654321]'::vector::halfvec AS half_vec;
-- Cast Float16 to Float32 (expands precision)
SELECT '[0.123, 0.987]'::halfvec::vector AS full_vec;
Round-Trip ConversionsΒΆ
-- Dense -> Sparse -> Dense (preserves values)
SELECT '[0.1, 0, 0.3]'::vector::sparsevec::vector AS round_trip;
-- Vector -> Binary -> Vector (loses precision, binary quantization)
SELECT '[0.1, -0.2, 0.3]'::vector::bit::vector AS quantized;
Query ExamplesΒΆ
Example 1: Semantic SearchΒΆ
-- Find documents similar to a query
SELECT
id,
title,
content,
embedding <=> '[0.1, 0.2, 0.3, ...]'::vector AS similarity
FROM documents
WHERE language = 'en'
ORDER BY similarity
LIMIT 20;
Example 2: Hybrid Search with Multiple FiltersΒΆ
-- Find similar documents with complex filters
SELECT
d.id,
d.title,
d.embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance,
d.published_date
FROM documents d
WHERE d.category IN ('science', 'technology')
AND d.published_date BETWEEN '2024-01-01' AND '2024-12-31'
AND d.author_id IN (SELECT id FROM authors WHERE verified = true)
ORDER BY distance
LIMIT 10;
Example 3: Clustering AnalysisΒΆ
-- Find cluster centroids and assign documents
WITH cluster_centroids AS (
SELECT
cluster_id,
vector_avg(embedding) AS centroid
FROM documents
GROUP BY cluster_id
),
document_distances AS (
SELECT
d.id,
d.cluster_id AS assigned_cluster,
c.cluster_id AS nearest_cluster,
d.embedding <-> c.centroid AS distance,
ROW_NUMBER() OVER (PARTITION BY d.id ORDER BY d.embedding <-> c.centroid) AS rank
FROM documents d
CROSS JOIN cluster_centroids c
)
SELECT
id,
assigned_cluster,
nearest_cluster,
distance
FROM document_distances
WHERE rank = 1 AND assigned_cluster != nearest_cluster;
Example 4: Recommendation SystemΒΆ
-- Find similar items based on user preferences
WITH user_profile AS (
SELECT vector_avg(i.embedding) AS preference_vector
FROM user_interactions ui
JOIN items i ON ui.item_id = i.id
WHERE ui.user_id = 123
AND ui.rating >= 4
)
SELECT
i.id,
i.name,
i.embedding <#> up.preference_vector AS score
FROM items i
CROSS JOIN user_profile up
WHERE i.id NOT IN (
SELECT item_id FROM user_interactions WHERE user_id = 123
)
ORDER BY score DESC
LIMIT 20;
Example 5: DeduplicationΒΆ
-- Find near-duplicate documents
SELECT
d1.id AS doc1_id,
d2.id AS doc2_id,
d1.embedding <-> d2.embedding AS distance
FROM documents d1
JOIN documents d2 ON d1.id < d2.id
WHERE d1.embedding <-> d2.embedding < 0.1
ORDER BY distance;
Example 6: Multi-Vector SearchΒΆ
-- Search across multiple vector columns
SELECT
id,
title,
LEAST(
text_embedding <=> '[0.1, 0.2, ...]'::vector,
image_embedding <=> '[0.3, 0.4, ...]'::vector
) AS min_distance
FROM multimedia_documents
ORDER BY min_distance
LIMIT 10;
Example 7: Temporal Vector SearchΒΆ
-- Find similar documents with time decay
SELECT
id,
title,
embedding <-> '[0.1, 0.2, 0.3]'::vector AS distance,
EXTRACT(EPOCH FROM (NOW() - published_date)) / 86400 AS days_old,
(embedding <-> '[0.1, 0.2, 0.3]'::vector) *
(1 + 0.01 * EXTRACT(EPOCH FROM (NOW() - published_date)) / 86400) AS time_weighted_distance
FROM documents
ORDER BY time_weighted_distance
LIMIT 10;
Performance TipsΒΆ
Index UsageΒΆ
Ensure indexes exist: Vector searches automatically use HNSW or IVF indexes when available
Monitor fallback: Check logs for βusing sequential scanβ messages indicating missing indexes
Tune parameters: Adjust
ef_searchandprobesbased on accuracy/speed requirements
Query OptimizationΒΆ
Use filters early: Scalar filters are applied before vector search for better performance
Limit results: Always use
LIMITfor KNN queries to enable index optimizationProject only needed columns: Avoid
SELECT *when working with large embeddings
Data TypesΒΆ
Use sparse vectors: For high-dimensional vectors with >90% zeros
Use binary vectors: For memory-constrained environments (32x compression)
Use Float16: For 2x memory savings with acceptable precision loss
Error HandlingΒΆ
Common ErrorsΒΆ
Dimension Mismatch:
-- Error: Vector dimension mismatch: expected 768, got 512
SELECT embedding <-> '[0.1, 0.2]'::vector FROM documents;
Malformed Literal:
-- Error: Vector literal must be enclosed in brackets
SELECT '[0.1, 0.2'::vector;
-- Error: Invalid number at position 5
SELECT '[0.1, abc]'::vector;
Invalid Cast:
-- Error: Cannot cast string to vector without proper format
SELECT 'not a vector'::vector;
Aggregation Dimension Mismatch:
-- Error: Cannot aggregate vectors of different dimensions
SELECT vector_avg(embedding) FROM mixed_dimension_table;
TroubleshootingΒΆ
Check vector dimensions: Use
vector_dims(column)to verify dimensionsValidate data: Ensure no NaN or infinite values in vectors
Test with small data: Verify queries on small datasets before scaling
Check configuration: Verify
ef_searchandprobesare positive integers
Compatibility Notes & ConversionsΒΆ
pgvector Compatibility MatrixΒΆ
BenoStreamDB implements the pgvector SQL interface with the following behavior:
Feature / Operator |
BenoStreamDB |
PostgreSQL + pgvector |
Notes |
|---|---|---|---|
|
β
Direct on |
β
Direct on |
100% 1-to-1 drop-in syntax |
|
β
Direct on |
β
Direct on |
100% 1-to-1 drop-in syntax |
|
β
Direct on |
β
Direct on |
100% 1-to-1 drop-in syntax |
|
β
Direct on |
β
Direct on |
Added in pgvector 0.7.0+ |
|
β
Enhanced: Direct on |
β οΈ |
BenoStreamDB evaluates on float indicators directly; PostgreSQL requires |
|
β
Enhanced: Direct on |
β οΈ |
BenoStreamDB evaluates on float indicator sets directly; PostgreSQL requires |
Vector Literals |
|
|
Compatible |
KNN Pushdown |
|
|
Compatible |
Vector Aggregations |
|
|
Compatible |
Exact PostgreSQL Conversion GuideΒΆ
If you are porting queries between BenoStreamDB and PostgreSQL with pgvector, use the exact conversions below:
1. Standard Distance Operators (<->, <=>, <#>, <+>)ΒΆ
These operators share identical semantics and syntax between engines:
-- BenoStreamDB:
SELECT id, content FROM documents
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10;
-- PostgreSQL (pgvector):
SELECT id, content FROM documents
ORDER BY embedding <-> '[0.1, 0.2, 0.3]'::vector
LIMIT 10;
2. Hamming Distance (<~>)ΒΆ
BenoStreamDB: Directly calculates Hamming distance over standard float embeddings or binary indicator vectors.
PostgreSQL (pgvector):
<~>is strictly typed for PostgreSQLβsbittype. You must convert float vectors usingbinary_quantize()(or store the column asbit(N)):
-- BenoStreamDB (direct on ::vector):
SELECT id, content FROM documents
ORDER BY embedding <~> '[1, 0, 1]'::vector
LIMIT 10;
-- Equivalent PostgreSQL (pgvector 0.7.0+):
SELECT id, content FROM documents
ORDER BY binary_quantize(embedding) <~> binary_quantize('[1, 0, 1]'::vector)
LIMIT 10;
-- If your table in PostgreSQL already stores native bit columns:
SELECT id, content FROM documents
ORDER BY bit_embedding <~> '101'::bit(3)
LIMIT 10;
3. Jaccard Distance (<%>)ΒΆ
BenoStreamDB: Evaluates Jaccard set distance ($1.0 - \frac{\text{intersection}}{\text{union}}$) directly on float binary indicator vectors (where values $> 0.0$ represent set membership).
PostgreSQL (pgvector):
<%>is strictly typed for thebittype. Convert viabinary_quantize():
-- BenoStreamDB (direct on ::vector):
SELECT id, content FROM documents
ORDER BY embedding <%> '[1, 0, 1]'::vector
LIMIT 10;
-- Equivalent PostgreSQL (pgvector 0.7.0+):
SELECT id, content FROM documents
ORDER BY binary_quantize(embedding) <%> binary_quantize('[1, 0, 1]'::vector)
LIMIT 10;
-- If your table in PostgreSQL already stores native bit columns:
SELECT id, content FROM documents
ORDER BY bit_embedding <%> '101'::bit(3)
LIMIT 10;
Additional ResourcesΒΆ
BenoStreamDB Architecture
Vector Search Best Practices