Introduction
The pineconer package provides an R interface to the Pinecone Vector Database, a managed
vector database designed for machine learning applications. This
vignette demonstrates how to use pineconer for common
vector database operations using the classic iris dataset.
Setup
Installation
# Install from GitHub (when available)
# remotes::install_github("bob-rietveld/pineconer")API Key Configuration
Before using pineconer, you need to set your Pinecone
API key. Add it to your ~/.Renviron file:
PINECONE_API_KEY=your_api_key_here
Then restart R or run:
readRenviron("~/.Renviron")Load the package:
Working with Indexes
List Existing Indexes
# List all indexes in your project
indexes <- list_indexes()
print(indexes$content)Create an Index
Pinecone supports two types of indexes: serverless and pod-based.
Serverless Index (Recommended)
# Create a serverless index for storing 4-dimensional vectors (like iris features)
result <- create_index(
name = "iris-demo",
dimension = 4,
metric = "cosine",
spec = list(
serverless = list(
cloud = "aws",
region = "us-east-1"
)
)
)
print(result$status_code) # 201 on successPod-Based Index
# Alternative: Create a pod-based index
result <- create_index(
name = "iris-pod-demo",
dimension = 4,
metric = "cosine",
spec = list(
pod = list(
environment = "us-east-1-aws",
pod_type = "p1.x1",
pods = 1
)
)
)Describe an Index
# Get index details including the host for data operations
index_info <- describe_index("iris-demo")
print(index_info$content$host)
print(index_info$content$status)Vector Operations with the Iris Dataset
The iris dataset contains 150 observations with 4 numeric features, making it ideal for demonstrating vector operations.
Preparing Data
# Load iris dataset
data(iris)
# Prepare vectors for upserting
vectors <- lapply(1:nrow(iris), function(i) {
list(
id = paste0("iris-", i),
values = as.numeric(iris[i, 1:4]),
metadata = list(
species = as.character(iris$Species[i]),
sepal_length = iris$Sepal.Length[i],
sepal_width = iris$Sepal.Width[i]
)
)
})
# Preview first vector
print(vectors[[1]])Upsert Vectors
# Upsert vectors in batches (Pinecone recommends batches of 100)
batch_size <- 100
n_batches <- ceiling(length(vectors) / batch_size)
for (i in 1:n_batches) {
start_idx <- (i - 1) * batch_size + 1
end_idx <- min(i * batch_size, length(vectors))
result <- vector_upsert(
index = "iris-demo",
vectors = vectors[start_idx:end_idx]
)
cat("Batch", i, "- Status:", result$status_code, "\n")
}Query Vectors
Find similar flowers based on their measurements:
# Query using a sample vector (first iris observation)
query_vector <- as.numeric(iris[1, 1:4])
results <- vector_query(
index = "iris-demo",
vector = query_vector,
top_k = 5,
include_metadata = TRUE
)
# Results are returned as a tidy tibble by default
print(results$content)Query with Metadata Filters
# Find similar vectors but only among setosa species
results <- vector_query(
index = "iris-demo",
vector = query_vector,
top_k = 5,
filter = list(species = list(`$eq` = "setosa"))
)
print(results$content)Fetch Specific Vectors
# Fetch vectors by ID
fetched <- vector_fetch(
index = "iris-demo",
ids = c("iris-1", "iris-2", "iris-3")
)
print(fetched$content)Update Vector Metadata
# Update metadata for a specific vector
result <- vector_update(
index = "iris-demo",
vector_id = "iris-1",
meta_data = list(
species = "setosa",
sepal_length = 5.1,
verified = TRUE
)
)
print(result$status_code) # 200 on successGet Index Statistics
# Get statistics about the index
stats <- describe_index_stats("iris-demo")
print(stats$content$totalVectorCount)
print(stats$content$dimension)Delete Vectors
# Delete specific vectors
result <- vector_delete(
index = "iris-demo",
ids = c("iris-1", "iris-2")
)
# Delete all vectors in a namespace
result <- vector_delete(
index = "iris-demo",
delete_all = TRUE,
name_space = "test-namespace"
)Working with Collections
Collections are static snapshots of an index that can be used to create new indexes.
Create a Collection
# Create a collection from an existing index
result <- create_collection(
name = "iris-backup",
source = "iris-demo"
)
print(result$status_code)List Collections
collections <- list_collections()
print(collections$content)Describe a Collection
collection_info <- describe_collection("iris-backup")
print(collection_info$content)Working with Namespaces
Namespaces allow you to partition vectors within an index:
# Upsert to a specific namespace
result <- vector_upsert(
index = "iris-demo",
vectors = vectors[1:50],
name_space = "training"
)
result <- vector_upsert(
index = "iris-demo",
vectors = vectors[51:100],
name_space = "validation"
)
# Query a specific namespace
results <- vector_query(
index = "iris-demo",
vector = query_vector,
top_k = 5,
name_space = "training"
)Cleanup
# Delete the index when done
delete_index("iris-demo")
# Delete the collection
delete_collection("iris-backup")Error Handling
All functions return a consistent response structure:
result <- describe_index("non-existent-index")
if (result$status_code != 200) {
cat("Error:", result$status_code, "\n")
# Access raw response for details
print(httr::content(result$http))
} else {
print(result$content)
}Tips and Best Practices
Batch Operations: When upserting many vectors, use batches of 100 for optimal performance.
Dimension Consistency: Ensure all vectors have the same dimension as defined when creating the index.
Metadata: Use metadata for filtering queries. Common patterns include categories, timestamps, and source identifiers.
Namespaces: Use namespaces to logically separate data (e.g., by user, environment, or data source).
Index Hosting: Store the index host from
describe_index()to avoid repeated API calls.