vectra-client 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/CHANGELOG.md +13 -8
- data/docs/_layouts/default.html +1 -0
- data/docs/_layouts/home.html +44 -3
- data/docs/_layouts/page.html +42 -9
- data/docs/assets/style.css +226 -1
- data/docs/examples/index.md +9 -0
- data/docs/examples/real-world.md +536 -0
- data/docs/grafana_final.png +0 -0
- data/docs/guides/monitoring.md +50 -0
- data/examples/GRAFANA_QUICKSTART.md +158 -0
- data/examples/README.md +320 -0
- data/examples/comprehensive_demo.rb +1116 -0
- data/examples/grafana-dashboard.json +878 -0
- data/examples/grafana-setup.md +340 -0
- data/examples/prometheus-exporter.rb +229 -0
- data/lib/vectra/providers/weaviate.rb +454 -10
- data/lib/vectra/version.rb +1 -1
- data/vectra.gemspec +56 -0
- metadata +10 -1
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Real-World Examples
|
|
4
|
+
permalink: /examples/real-world/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Real-World Examples
|
|
8
|
+
|
|
9
|
+
Production-ready examples demonstrating Vectra in real-world scenarios.
|
|
10
|
+
|
|
11
|
+
## E-Commerce Product Search
|
|
12
|
+
|
|
13
|
+
Semantic product search with filtering, caching, and performance optimization.
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
require "vectra"
|
|
17
|
+
|
|
18
|
+
class ProductSearchService
|
|
19
|
+
def initialize
|
|
20
|
+
@client = Vectra.pinecone(
|
|
21
|
+
api_key: ENV["PINECONE_API_KEY"],
|
|
22
|
+
environment: "us-east-1"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Performance optimizations
|
|
26
|
+
@cache = Vectra::Cache.new(ttl: 600, max_size: 5000)
|
|
27
|
+
@cached_client = Vectra::CachedClient.new(@client, cache: @cache)
|
|
28
|
+
|
|
29
|
+
# Resilience patterns
|
|
30
|
+
@rate_limiter = Vectra::RateLimiter.new(requests_per_second: 100)
|
|
31
|
+
@circuit_breaker = Vectra::CircuitBreaker.new(
|
|
32
|
+
name: "product-search",
|
|
33
|
+
failure_threshold: 5,
|
|
34
|
+
recovery_timeout: 60
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def search(query:, category: nil, price_range: nil, limit: 20)
|
|
39
|
+
query_embedding = generate_embedding(query)
|
|
40
|
+
|
|
41
|
+
filter = {}
|
|
42
|
+
filter[:category] = category if category
|
|
43
|
+
filter[:price_min] = price_range[:min] if price_range&.dig(:min)
|
|
44
|
+
filter[:price_max] = price_range[:max] if price_range&.dig(:max)
|
|
45
|
+
|
|
46
|
+
@rate_limiter.acquire do
|
|
47
|
+
@circuit_breaker.call do
|
|
48
|
+
@cached_client.query(
|
|
49
|
+
index: "products",
|
|
50
|
+
vector: query_embedding,
|
|
51
|
+
top_k: limit,
|
|
52
|
+
filter: filter,
|
|
53
|
+
include_metadata: true
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
rescue Vectra::RateLimitError => e
|
|
58
|
+
# Handle rate limiting gracefully
|
|
59
|
+
Rails.logger.warn("Rate limit hit: #{e.retry_after}s")
|
|
60
|
+
sleep(e.retry_after || 1)
|
|
61
|
+
retry
|
|
62
|
+
rescue Vectra::CircuitBreakerOpenError
|
|
63
|
+
# Fallback to cached results or alternative search
|
|
64
|
+
fallback_search(query, category)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def generate_embedding(text)
|
|
70
|
+
# Use your embedding model (OpenAI, sentence-transformers, etc.)
|
|
71
|
+
OpenAI::Client.new.embeddings(
|
|
72
|
+
parameters: { model: "text-embedding-ada-002", input: text }
|
|
73
|
+
)["data"][0]["embedding"]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def fallback_search(query, category)
|
|
77
|
+
# Fallback to database search or cached results
|
|
78
|
+
Product.where("name ILIKE ?", "%#{query}%")
|
|
79
|
+
.where(category: category)
|
|
80
|
+
.limit(20)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Usage
|
|
85
|
+
service = ProductSearchService.new
|
|
86
|
+
results = service.search(
|
|
87
|
+
query: "wireless headphones with noise cancellation",
|
|
88
|
+
category: "Electronics",
|
|
89
|
+
price_range: { min: 50, max: 200 }
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
results.each do |product|
|
|
93
|
+
puts "#{product.metadata[:name]} - $#{product.metadata[:price]}"
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## RAG Chatbot with Streaming
|
|
98
|
+
|
|
99
|
+
Retrieval-Augmented Generation chatbot with streaming responses and error handling.
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
require "vectra"
|
|
103
|
+
|
|
104
|
+
class RAGChatbot
|
|
105
|
+
def initialize
|
|
106
|
+
@vectra_client = Vectra.qdrant(
|
|
107
|
+
host: ENV["QDRANT_HOST"],
|
|
108
|
+
api_key: ENV["QDRANT_API_KEY"]
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
@llm_client = OpenAI::Client.new
|
|
112
|
+
@streaming = Vectra::Streaming.new(@vectra_client)
|
|
113
|
+
|
|
114
|
+
# Monitoring
|
|
115
|
+
Vectra::Instrumentation::Sentry.setup! if defined?(Sentry)
|
|
116
|
+
Vectra::Logging.setup!(output: "log/chatbot.json.log")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def chat(user_message:, conversation_id:, &block)
|
|
120
|
+
# 1. Retrieve relevant context
|
|
121
|
+
context = retrieve_context(user_message, limit: 5)
|
|
122
|
+
|
|
123
|
+
# 2. Build prompt with context
|
|
124
|
+
prompt = build_prompt(user_message, context)
|
|
125
|
+
|
|
126
|
+
# 3. Stream LLM response
|
|
127
|
+
stream_llm_response(prompt, conversation_id, &block)
|
|
128
|
+
|
|
129
|
+
# 4. Log interaction
|
|
130
|
+
log_interaction(user_message, context, conversation_id)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
def retrieve_context(query, limit:)
|
|
136
|
+
query_embedding = generate_embedding(query)
|
|
137
|
+
|
|
138
|
+
results = @streaming.query_each(
|
|
139
|
+
index: "knowledge_base",
|
|
140
|
+
vector: query_embedding,
|
|
141
|
+
top_k: limit,
|
|
142
|
+
batch_size: 10,
|
|
143
|
+
include_metadata: true
|
|
144
|
+
) do |batch|
|
|
145
|
+
# Process in batches for memory efficiency
|
|
146
|
+
batch
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
results.map { |r| r.metadata[:content] }.join("\n\n")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def build_prompt(user_message, context)
|
|
153
|
+
<<~PROMPT
|
|
154
|
+
You are a helpful assistant. Use the following context to answer the question.
|
|
155
|
+
|
|
156
|
+
Context:
|
|
157
|
+
#{context}
|
|
158
|
+
|
|
159
|
+
Question: #{user_message}
|
|
160
|
+
|
|
161
|
+
Answer:
|
|
162
|
+
PROMPT
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def stream_llm_response(prompt, conversation_id, &block)
|
|
166
|
+
@llm_client.chat(
|
|
167
|
+
parameters: {
|
|
168
|
+
model: "gpt-4",
|
|
169
|
+
messages: [{ role: "user", content: prompt }],
|
|
170
|
+
stream: proc { |chunk, _bytesize|
|
|
171
|
+
block.call(chunk) if block
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def log_interaction(user_message, context, conversation_id)
|
|
178
|
+
Vectra::Logging.log_info(
|
|
179
|
+
"Chat interaction",
|
|
180
|
+
conversation_id: conversation_id,
|
|
181
|
+
query_length: user_message.length,
|
|
182
|
+
context_snippets: context.split("\n\n").size
|
|
183
|
+
)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def generate_embedding(text)
|
|
187
|
+
# Embedding generation
|
|
188
|
+
@llm_client.embeddings(
|
|
189
|
+
parameters: { model: "text-embedding-ada-002", input: text }
|
|
190
|
+
)["data"][0]["embedding"]
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Usage with streaming
|
|
195
|
+
chatbot = RAGChatbot.new
|
|
196
|
+
|
|
197
|
+
chatbot.chat(
|
|
198
|
+
user_message: "How do I implement authentication in Rails?",
|
|
199
|
+
conversation_id: "conv-123"
|
|
200
|
+
) do |chunk|
|
|
201
|
+
print chunk.dig("choices", 0, "delta", "content")
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Multi-Tenant SaaS Application
|
|
206
|
+
|
|
207
|
+
SaaS application with tenant isolation, audit logging, and health monitoring.
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
require "vectra"
|
|
211
|
+
|
|
212
|
+
class TenantDocumentService
|
|
213
|
+
def initialize(tenant_id:)
|
|
214
|
+
@tenant_id = tenant_id
|
|
215
|
+
@client = Vectra.pgvector(
|
|
216
|
+
connection_url: ENV["DATABASE_URL"],
|
|
217
|
+
pool_size: 10
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Audit logging for compliance
|
|
221
|
+
@audit = Vectra::AuditLog.new(
|
|
222
|
+
output: "log/audit.json.log",
|
|
223
|
+
enabled: true
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Health monitoring
|
|
227
|
+
@health_checker = Vectra::AggregateHealthCheck.new(
|
|
228
|
+
primary: @client
|
|
229
|
+
)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def index_document(document_id:, content:, metadata: {})
|
|
233
|
+
embedding = generate_embedding(content)
|
|
234
|
+
|
|
235
|
+
result = @client.upsert(
|
|
236
|
+
index: "documents",
|
|
237
|
+
vectors: [{
|
|
238
|
+
id: document_id,
|
|
239
|
+
values: embedding,
|
|
240
|
+
metadata: metadata.merge(tenant_id: @tenant_id)
|
|
241
|
+
}],
|
|
242
|
+
namespace: "tenant-#{@tenant_id}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
# Audit log
|
|
246
|
+
@audit.log_data_modification(
|
|
247
|
+
user_id: current_user&.id,
|
|
248
|
+
operation: "upsert",
|
|
249
|
+
index: "documents",
|
|
250
|
+
record_count: 1
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
result
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def search_documents(query:, limit: 20)
|
|
257
|
+
query_embedding = generate_embedding(query)
|
|
258
|
+
|
|
259
|
+
# Ensure tenant isolation via namespace
|
|
260
|
+
results = @client.query(
|
|
261
|
+
index: "documents",
|
|
262
|
+
vector: query_embedding,
|
|
263
|
+
top_k: limit,
|
|
264
|
+
namespace: "tenant-#{@tenant_id}",
|
|
265
|
+
filter: { tenant_id: @tenant_id }, # Double protection
|
|
266
|
+
include_metadata: true
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Audit log
|
|
270
|
+
@audit.log_access(
|
|
271
|
+
user_id: current_user&.id,
|
|
272
|
+
operation: "query",
|
|
273
|
+
index: "documents",
|
|
274
|
+
result_count: results.size
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
results
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def health_status
|
|
281
|
+
@health_checker.check_all
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
|
|
286
|
+
def generate_embedding(text)
|
|
287
|
+
# Your embedding generation
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Usage per tenant
|
|
292
|
+
tenant_service = TenantDocumentService.new(tenant_id: "acme-corp")
|
|
293
|
+
|
|
294
|
+
# Index document (isolated to tenant)
|
|
295
|
+
tenant_service.index_document(
|
|
296
|
+
document_id: "doc-123",
|
|
297
|
+
content: "Important business document...",
|
|
298
|
+
metadata: { title: "Q4 Report", category: "Finance" }
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
# Search (only returns tenant's documents)
|
|
302
|
+
results = tenant_service.search_documents(query: "financial report")
|
|
303
|
+
|
|
304
|
+
# Health check
|
|
305
|
+
health = tenant_service.health_status
|
|
306
|
+
puts "System healthy: #{health[:overall_healthy]}"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## High-Performance Batch Processing
|
|
310
|
+
|
|
311
|
+
Processing large datasets with async batch operations and progress tracking.
|
|
312
|
+
|
|
313
|
+
```ruby
|
|
314
|
+
require "vectra"
|
|
315
|
+
|
|
316
|
+
class DocumentIndexer
|
|
317
|
+
def initialize
|
|
318
|
+
@client = Vectra.pinecone(
|
|
319
|
+
api_key: ENV["PINECONE_API_KEY"],
|
|
320
|
+
environment: "us-east-1"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
@batch_client = Vectra::Batch.new(@client)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def index_large_dataset(documents, concurrency: 4)
|
|
327
|
+
total = documents.size
|
|
328
|
+
processed = 0
|
|
329
|
+
errors = []
|
|
330
|
+
|
|
331
|
+
# Convert to vectors
|
|
332
|
+
vectors = documents.map do |doc|
|
|
333
|
+
{
|
|
334
|
+
id: doc[:id],
|
|
335
|
+
values: generate_embedding(doc[:content]),
|
|
336
|
+
metadata: doc[:metadata]
|
|
337
|
+
}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Process in async batches
|
|
341
|
+
result = @batch_client.upsert_async(
|
|
342
|
+
index: "documents",
|
|
343
|
+
vectors: vectors,
|
|
344
|
+
concurrency: concurrency,
|
|
345
|
+
on_progress: proc { |success, failed, total|
|
|
346
|
+
processed = success + failed
|
|
347
|
+
progress = (processed.to_f / total * 100).round(1)
|
|
348
|
+
puts "Progress: #{progress}% (#{processed}/#{total})"
|
|
349
|
+
},
|
|
350
|
+
on_error: proc { |error, vector|
|
|
351
|
+
errors << { id: vector[:id], error: error.message }
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
{
|
|
356
|
+
success: result[:success],
|
|
357
|
+
failed: result[:failed],
|
|
358
|
+
errors: errors,
|
|
359
|
+
total: total
|
|
360
|
+
}
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
private
|
|
364
|
+
|
|
365
|
+
def generate_embedding(text)
|
|
366
|
+
# Embedding generation
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Usage
|
|
371
|
+
indexer = DocumentIndexer.new
|
|
372
|
+
|
|
373
|
+
# Index 10,000 documents with 4 concurrent workers
|
|
374
|
+
result = indexer.index_large_dataset(
|
|
375
|
+
large_document_array,
|
|
376
|
+
concurrency: 4
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
puts "Indexed: #{result[:success]}"
|
|
380
|
+
puts "Failed: #{result[:failed]}"
|
|
381
|
+
puts "Errors: #{result[:errors].size}"
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Production-Ready Configuration
|
|
385
|
+
|
|
386
|
+
Complete production setup with all monitoring, resilience, and performance features.
|
|
387
|
+
|
|
388
|
+
```ruby
|
|
389
|
+
# config/initializers/vectra.rb
|
|
390
|
+
require "vectra"
|
|
391
|
+
|
|
392
|
+
Vectra.configure do |config|
|
|
393
|
+
config.provider = :pinecone
|
|
394
|
+
config.api_key = Rails.application.credentials.dig(:vectra, :api_key)
|
|
395
|
+
config.environment = ENV["PINECONE_ENVIRONMENT"] || "us-east-1"
|
|
396
|
+
|
|
397
|
+
# Performance
|
|
398
|
+
config.cache_enabled = true
|
|
399
|
+
config.cache_ttl = 600
|
|
400
|
+
config.cache_max_size = 10000
|
|
401
|
+
config.async_concurrency = 4
|
|
402
|
+
config.batch_size = 100
|
|
403
|
+
|
|
404
|
+
# Resilience
|
|
405
|
+
config.max_retries = 3
|
|
406
|
+
config.retry_delay = 1
|
|
407
|
+
config.timeout = 30
|
|
408
|
+
|
|
409
|
+
# Logging
|
|
410
|
+
config.logger = Rails.logger
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Setup monitoring
|
|
414
|
+
if defined?(Sentry)
|
|
415
|
+
Vectra::Instrumentation::Sentry.setup!
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
if defined?(Honeybadger)
|
|
419
|
+
Vectra::Instrumentation::Honeybadger.setup!
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# Setup structured logging
|
|
423
|
+
Vectra::Logging.setup!(
|
|
424
|
+
output: Rails.root.join("log", "vectra.json.log"),
|
|
425
|
+
app: Rails.application.class.module_parent_name,
|
|
426
|
+
env: Rails.env
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
# Setup audit logging
|
|
430
|
+
Vectra::AuditLogging.setup!(
|
|
431
|
+
output: Rails.root.join("log", "audit.json.log"),
|
|
432
|
+
enabled: Rails.env.production?,
|
|
433
|
+
app: Rails.application.class.module_parent_name,
|
|
434
|
+
env: Rails.env
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
# Global rate limiter
|
|
438
|
+
$vectra_rate_limiter = Vectra::RateLimiter.new(
|
|
439
|
+
requests_per_second: ENV.fetch("VECTRA_RATE_LIMIT", 100).to_i,
|
|
440
|
+
burst_size: ENV.fetch("VECTRA_BURST_SIZE", 200).to_i
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
# Global circuit breaker
|
|
444
|
+
$vectra_circuit_breaker = Vectra::CircuitBreaker.new(
|
|
445
|
+
name: "vectra-main",
|
|
446
|
+
failure_threshold: 5,
|
|
447
|
+
recovery_timeout: 60
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# Application helper
|
|
451
|
+
module VectraHelper
|
|
452
|
+
def vectra_client
|
|
453
|
+
@vectra_client ||= begin
|
|
454
|
+
client = Vectra::Client.new
|
|
455
|
+
cached = Vectra::CachedClient.new(client)
|
|
456
|
+
cached
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def safe_vectra_query(**args)
|
|
461
|
+
$vectra_rate_limiter.acquire do
|
|
462
|
+
$vectra_circuit_breaker.call do
|
|
463
|
+
vectra_client.query(**args)
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
rescue Vectra::CircuitBreakerOpenError
|
|
467
|
+
# Fallback logic
|
|
468
|
+
Rails.logger.error("Circuit breaker open, using fallback")
|
|
469
|
+
fallback_search(args)
|
|
470
|
+
rescue Vectra::RateLimitError => e
|
|
471
|
+
Rails.logger.warn("Rate limit: #{e.retry_after}s")
|
|
472
|
+
sleep(e.retry_after || 1)
|
|
473
|
+
retry
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Best Practices
|
|
479
|
+
|
|
480
|
+
### 1. Always Use Caching for Frequent Queries
|
|
481
|
+
|
|
482
|
+
```ruby
|
|
483
|
+
cache = Vectra::Cache.new(ttl: 600, max_size: 10000)
|
|
484
|
+
cached_client = Vectra::CachedClient.new(client, cache: cache)
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### 2. Implement Rate Limiting
|
|
488
|
+
|
|
489
|
+
```ruby
|
|
490
|
+
limiter = Vectra::RateLimiter.new(requests_per_second: 100)
|
|
491
|
+
limiter.acquire { client.query(...) }
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### 3. Use Circuit Breaker for Resilience
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
breaker = Vectra::CircuitBreaker.new(failure_threshold: 5)
|
|
498
|
+
breaker.call { client.query(...) }
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### 4. Enable Monitoring
|
|
502
|
+
|
|
503
|
+
```ruby
|
|
504
|
+
Vectra::Instrumentation::Sentry.setup!
|
|
505
|
+
Vectra::Logging.setup!(output: "log/vectra.json.log")
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### 5. Audit Critical Operations
|
|
509
|
+
|
|
510
|
+
```ruby
|
|
511
|
+
audit = Vectra::AuditLog.new(output: "log/audit.json.log")
|
|
512
|
+
audit.log_access(user_id: user.id, operation: "query", index: "docs")
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### 6. Use Streaming for Large Queries
|
|
516
|
+
|
|
517
|
+
```ruby
|
|
518
|
+
streaming = Vectra::Streaming.new(client)
|
|
519
|
+
streaming.query_each(index: "docs", vector: vec, batch_size: 100) do |batch|
|
|
520
|
+
process_batch(batch)
|
|
521
|
+
end
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### 7. Health Checks in Production
|
|
525
|
+
|
|
526
|
+
```ruby
|
|
527
|
+
health = client.health_check(include_stats: true)
|
|
528
|
+
raise "Unhealthy" unless health.healthy?
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## Next Steps
|
|
532
|
+
|
|
533
|
+
- [Comprehensive Demo](../examples/) - Full feature demonstration
|
|
534
|
+
- [Performance Guide](../guides/performance/) - Optimization strategies
|
|
535
|
+
- [Monitoring Guide](../guides/monitoring/) - Production monitoring
|
|
536
|
+
- [Security Guide](../guides/security/) - Security best practices
|
|
Binary file
|
data/docs/guides/monitoring.md
CHANGED
|
@@ -138,6 +138,56 @@ run YourApp
|
|
|
138
138
|
|
|
139
139
|
## Grafana Dashboard
|
|
140
140
|
|
|
141
|
+
### Live Dashboard Preview
|
|
142
|
+
|
|
143
|
+
Vectra includes a comprehensive Grafana dashboard with 11 professional panels for monitoring all aspects of your vector database operations:
|
|
144
|
+
|
|
145
|
+
<div class="tma-dashboard-showcase">
|
|
146
|
+
<div class="tma-dashboard-showcase__image">
|
|
147
|
+
<img src="{{ site.baseurl }}/grafana_final.png" alt="Vectra Grafana Dashboard - Real-time monitoring of vector database operations" class="tma-dashboard-screenshot">
|
|
148
|
+
</div>
|
|
149
|
+
<div class="tma-dashboard-showcase__features">
|
|
150
|
+
<h4>Dashboard Features</h4>
|
|
151
|
+
<ul>
|
|
152
|
+
<li><strong>Real-time Metrics:</strong> Request rate, latency, error tracking</li>
|
|
153
|
+
<li><strong>Performance Monitoring:</strong> P50, P95, P99 latency percentiles</li>
|
|
154
|
+
<li><strong>Cache Analytics:</strong> Hit ratio and performance metrics</li>
|
|
155
|
+
<li><strong>Provider Insights:</strong> Multi-provider comparison and distribution</li>
|
|
156
|
+
<li><strong>Connection Pooling:</strong> pgvector pool status and utilization</li>
|
|
157
|
+
<li><strong>Visual Analytics:</strong> Time series, pie charts, bar gauges</li>
|
|
158
|
+
</ul>
|
|
159
|
+
<div class="tma-dashboard-showcase__actions">
|
|
160
|
+
<a href="https://github.com/stokry/vectra/tree/main/examples#grafana-dashboard" class="tma-button tma-button--primary" target="_blank" rel="noopener">
|
|
161
|
+
Get Dashboard JSON →
|
|
162
|
+
</a>
|
|
163
|
+
<a href="https://github.com/stokry/vectra/blob/main/examples/GRAFANA_QUICKSTART.md" class="tma-button tma-button--secondary" target="_blank" rel="noopener">
|
|
164
|
+
Quick Start Guide →
|
|
165
|
+
</a>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
### Quick Setup
|
|
171
|
+
|
|
172
|
+
Get started in 5 minutes:
|
|
173
|
+
|
|
174
|
+
1. **Start Prometheus Exporter:**
|
|
175
|
+
```bash
|
|
176
|
+
gem install prometheus-client
|
|
177
|
+
ruby examples/prometheus-exporter.rb
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
2. **Import Dashboard:**
|
|
181
|
+
- Sign up at [grafana.com](https://grafana.com) (free tier available)
|
|
182
|
+
- Add Prometheus data source
|
|
183
|
+
- Import `examples/grafana-dashboard.json`
|
|
184
|
+
|
|
185
|
+
3. **View Metrics:**
|
|
186
|
+
- Dashboard populates with real-time data
|
|
187
|
+
- Perfect for monitoring and screenshots
|
|
188
|
+
|
|
189
|
+
See the [Quick Start Guide](https://github.com/stokry/vectra/blob/main/examples/GRAFANA_QUICKSTART.md) for detailed setup instructions.
|
|
190
|
+
|
|
141
191
|
### Dashboard JSON Template
|
|
142
192
|
|
|
143
193
|
Save as `vectra-dashboard.json` and import into Grafana:
|