vectra-client 1.0.6 → 1.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aada098f943da3a1b81288f46e32382e775492efc96e87a175b1e9ba002ea7c3
4
- data.tar.gz: 24f2efb3bdf110541c60ce4710f61e616fc824bf4874d8205ff5d1ebdaa8d9bc
3
+ metadata.gz: '05778206f66d4e2ead830f5b7c5885f6336b46d36af696f3df5a56eb26163c5f'
4
+ data.tar.gz: 1ae5814cd10df006ecf5568f34e457400b072ecc8a06dbf85a4e4f5b94120fb9
5
5
  SHA512:
6
- metadata.gz: 00df0da772c575e7933c97b640e0e6c1f31a5cdd7671b9f41106ccc54eda2b0f7e90871dd7ddbfe654ff9007fb5cc0b3a4897a0955284e0b4625c3dd1ddf9d3c
7
- data.tar.gz: d16d6c0425c8ba8ecad38021f416220c91a01bd4f58d8b0d397324dead8e9e3d32bc46b90583ac7678ecc2e0b2dcb0084dfad3b99fd021577c5c469ab07e8588
6
+ metadata.gz: d25889a4626c9caa9edf7ccc285c849799de87cf38a8a7a6f56a49edb46da592b28bc0232960e2612fd0d9199e990c21bd5fe6b88f15351d8ff38c73bd7afc84
7
+ data.tar.gz: d4ef355089814ed4caf8c61e216b9554f23035df12be72a65c778b3230bd2a32f16ecf4c50de3bc33e40dc323f1aee83d7a891ad962bec105585c8bc6b30902b
data/CHANGELOG.md CHANGED
@@ -1,14 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.0.8](https://github.com/stokry/vectra/tree/v1.0.8) (2026-01-14)
4
+
5
+ [Full Changelog](https://github.com/stokry/vectra/compare/v1.0.7...v1.0.8)
6
+
7
+ ## [v1.0.7](https://github.com/stokry/vectra/tree/v1.0.7) (2026-01-14)
8
+
9
+ [Full Changelog](https://github.com/stokry/vectra/compare/v1.0.6...v1.0.7)
10
+
3
11
  ## [v1.0.6](https://github.com/stokry/vectra/tree/v1.0.6) (2026-01-13)
4
12
 
5
13
  [Full Changelog](https://github.com/stokry/vectra/compare/v1.0.5...v1.0.6)
6
14
 
7
- ### Improvements
8
- - Refined test suite and documentation
9
- - Performance optimizations
10
- - Enhanced stability and reliability
11
-
12
15
  ## [v1.0.5](https://github.com/stokry/vectra/tree/v1.0.5) (2026-01-13)
13
16
 
14
17
  [Full Changelog](https://github.com/stokry/vectra/compare/v1.0.4...v1.0.5)
data/README.md CHANGED
@@ -229,6 +229,19 @@ For a complete step-by-step guide including:
229
229
 
230
230
  👉 **[Read the complete Rails Integration Guide](https://vectra-docs.netlify.app/guides/rails-integration/)**
231
231
 
232
+ ### Recipes & Patterns
233
+
234
+ Real-world patterns for common use cases:
235
+
236
+ - **E-Commerce Search** - Semantic product search with filters
237
+ - **Blog Hybrid Search** - Combine semantic + keyword matching
238
+ - **Multi-Tenant SaaS** - Namespace isolation per tenant
239
+ - **RAG Chatbot** - Context retrieval for LLMs
240
+ - **Zero-Downtime Migration** - Switch providers safely
241
+ - **Recommendation Engine** - Find similar items
242
+
243
+ 👉 **[Browse all Recipes & Patterns](https://vectra-docs.netlify.app/guides/recipes/)**
244
+
232
245
  ## Production Patterns
233
246
 
234
247
  Vectra includes 7 production-ready patterns out of the box:
@@ -40,6 +40,7 @@
40
40
  </button>
41
41
  <ul class="tma-nav__menu" id="nav-menu">
42
42
  <li><a href="{{ site.baseurl }}/guides/getting-started" class="tma-nav__link">Getting Started</a></li>
43
+ <li><a href="{{ site.baseurl }}/guides/recipes" class="tma-nav__link">Recipes</a></li>
43
44
  <li><a href="{{ site.baseurl }}/providers" class="tma-nav__link">Providers</a></li>
44
45
  <li><a href="{{ site.baseurl }}/api/overview" class="tma-nav__link">API</a></li>
45
46
  <li><a href="{{ site.baseurl }}/examples" class="tma-nav__link">Examples</a></li>
@@ -40,6 +40,7 @@
40
40
  </button>
41
41
  <ul class="tma-nav__menu" id="nav-menu">
42
42
  <li><a href="{{ site.baseurl }}/guides/getting-started" class="tma-nav__link">Getting Started</a></li>
43
+ <li><a href="{{ site.baseurl }}/guides/recipes" class="tma-nav__link">Recipes</a></li>
43
44
  <li><a href="{{ site.baseurl }}/providers" class="tma-nav__link">Providers</a></li>
44
45
  <li><a href="{{ site.baseurl }}/api/overview" class="tma-nav__link">API</a></li>
45
46
  <li><a href="{{ site.baseurl }}/examples" class="tma-nav__link">Examples</a></li>
@@ -568,6 +569,50 @@
568
569
  </div>
569
570
  </section>
570
571
 
572
+ <!-- Recipes Section -->
573
+ <section class="tma-recipes">
574
+ <div class="tma-section-header">
575
+ <h2 class="tma-section-header__title">Recipes & Patterns</h2>
576
+ <p class="tma-section-header__subtitle">Real-world patterns for common use cases</p>
577
+ </div>
578
+
579
+ <div class="tma-recipes__grid">
580
+ <a href="{{ site.baseurl }}/guides/recipes/#e-commerce-semantic-product-search-with-filters" class="tma-recipe-card">
581
+ <h3 class="tma-recipe-card__title">🛒 E-Commerce Search</h3>
582
+ <p class="tma-recipe-card__description">Semantic product search with filters for category, price, and availability</p>
583
+ </a>
584
+
585
+ <a href="{{ site.baseurl }}/guides/recipes/#blog-hybrid-search-semantic--keyword" class="tma-recipe-card">
586
+ <h3 class="tma-recipe-card__title">📝 Blog Hybrid Search</h3>
587
+ <p class="tma-recipe-card__description">Combine semantic understanding with exact keyword matching</p>
588
+ </a>
589
+
590
+ <a href="{{ site.baseurl }}/guides/recipes/#multi-tenant-saas-namespace-isolation" class="tma-recipe-card">
591
+ <h3 class="tma-recipe-card__title">🏢 Multi-Tenant SaaS</h3>
592
+ <p class="tma-recipe-card__description">Namespace isolation per tenant with a single index</p>
593
+ </a>
594
+
595
+ <a href="{{ site.baseurl }}/guides/recipes/#rag-chatbot-context-retrieval" class="tma-recipe-card">
596
+ <h3 class="tma-recipe-card__title">🤖 RAG Chatbot</h3>
597
+ <p class="tma-recipe-card__description">Retrieve relevant context chunks for LLM integration</p>
598
+ </a>
599
+
600
+ <a href="{{ site.baseurl }}/guides/recipes/#zero-downtime-provider-migration" class="tma-recipe-card">
601
+ <h3 class="tma-recipe-card__title">🔄 Provider Migration</h3>
602
+ <p class="tma-recipe-card__description">Zero-downtime migration between providers</p>
603
+ </a>
604
+
605
+ <a href="{{ site.baseurl }}/guides/recipes/#recommendation-engine-similar-items" class="tma-recipe-card">
606
+ <h3 class="tma-recipe-card__title">💡 Recommendations</h3>
607
+ <p class="tma-recipe-card__description">Find similar items based on user behavior</p>
608
+ </a>
609
+ </div>
610
+
611
+ <div style="text-align: center; margin-top: var(--tma-spacing-lg);">
612
+ <a href="{{ site.baseurl }}/guides/recipes" class="tma-btn tma-btn--secondary">View All Recipes →</a>
613
+ </div>
614
+ </section>
615
+
571
616
  <!-- Quick Start Code Section -->
572
617
  <section class="tma-code-section">
573
618
  <div class="tma-section-header">
@@ -40,6 +40,7 @@
40
40
  </button>
41
41
  <ul class="tma-nav__menu" id="nav-menu">
42
42
  <li><a href="{{ site.baseurl }}/guides/getting-started" class="tma-nav__link">Getting Started</a></li>
43
+ <li><a href="{{ site.baseurl }}/guides/recipes" class="tma-nav__link">Recipes</a></li>
43
44
  <li><a href="{{ site.baseurl }}/providers" class="tma-nav__link">Providers</a></li>
44
45
  <li><a href="{{ site.baseurl }}/api/overview" class="tma-nav__link">API</a></li>
45
46
  <li><a href="{{ site.baseurl }}/examples" class="tma-nav__link">Examples</a></li>
@@ -0,0 +1,387 @@
1
+ ---
2
+ layout: page
3
+ title: API Cheatsheet
4
+ permalink: /api/cheatsheet/
5
+ ---
6
+
7
+ # API Cheatsheet
8
+
9
+ Quick reference for the most important Vectra APIs.
10
+
11
+ > For full details, see the [API Overview](/api/overview/) and provider guides.
12
+
13
+ ## Core Client
14
+
15
+ ### Initialize Client
16
+
17
+ ```ruby
18
+ require 'vectra'
19
+
20
+ client = Vectra::Client.new(
21
+ provider: :qdrant, # :pinecone, :qdrant, :weaviate, :pgvector, :memory
22
+ api_key: ENV['QDRANT_API_KEY'],
23
+ host: 'http://localhost:6333',
24
+ environment: 'us-west-4' # For Pinecone
25
+ )
26
+ ```
27
+
28
+ Or use shortcuts:
29
+
30
+ ```ruby
31
+ client = Vectra.qdrant(host: 'http://localhost:6333')
32
+ client = Vectra.pinecone(api_key: ENV['PINECONE_API_KEY'], environment: 'us-west-4')
33
+ client = Vectra.pgvector(connection_url: ENV['DATABASE_URL'])
34
+ client = Vectra.memory # In-memory (testing only)
35
+ ```
36
+
37
+ You can also set a **default index and namespace**:
38
+
39
+ ```ruby
40
+ client = Vectra::Client.new(
41
+ provider: :qdrant,
42
+ host: 'http://localhost:6333',
43
+ index: 'products',
44
+ namespace: 'tenant-1'
45
+ )
46
+
47
+ # Now index and namespace can be omitted
48
+ client.upsert(vectors: [...])
49
+ client.query(vector: query_embedding, top_k: 10)
50
+ ```
51
+
52
+ ### Upsert
53
+
54
+ ```ruby
55
+ client.upsert(
56
+ index: 'documents',
57
+ vectors: [
58
+ {
59
+ id: 'doc-1',
60
+ values: embedding_array,
61
+ metadata: { title: 'Hello World', category: 'docs' }
62
+ }
63
+ ],
64
+ namespace: 'default' # optional
65
+ )
66
+ ```
67
+
68
+ ### Query (similarity search)
69
+
70
+ ```ruby
71
+ results = client.query(
72
+ index: 'documents',
73
+ vector: query_embedding,
74
+ top_k: 10,
75
+ filter: { category: 'docs' },
76
+ namespace: 'default',
77
+ include_values: false,
78
+ include_metadata: true
79
+ )
80
+
81
+ results.each do |match|
82
+ puts "#{match.id} (score=#{match.score.round(3)}): #{match.metadata['title']}"
83
+ end
84
+ ```
85
+
86
+ ### Hybrid Search (semantic + keyword)
87
+
88
+ ```ruby
89
+ results = client.hybrid_search(
90
+ index: 'documents',
91
+ vector: query_embedding,
92
+ text: 'ruby vector search',
93
+ alpha: 0.7, # 70% semantic, 30% keyword
94
+ top_k: 10,
95
+ filter: { category: 'blog' }
96
+ )
97
+ ```
98
+
99
+ Supported providers: Qdrant ✅, Weaviate ✅, pgvector ✅, Pinecone ⚠️
100
+
101
+ ### Fetch
102
+
103
+ ```ruby
104
+ vectors = client.fetch(
105
+ index: 'documents',
106
+ ids: ['doc-1', 'doc-2'],
107
+ namespace: 'default'
108
+ )
109
+
110
+ vectors['doc-1'].values # => [0.1, 0.2, ...]
111
+ vectors['doc-1'].metadata # => { 'title' => 'Hello World' }
112
+ ```
113
+
114
+ ### Update
115
+
116
+ ```ruby
117
+ client.update(
118
+ index: 'documents',
119
+ id: 'doc-1',
120
+ metadata: { category: 'guides' }
121
+ )
122
+ ```
123
+
124
+ ### Delete
125
+
126
+ ```ruby
127
+ # By IDs
128
+ client.delete(index: 'documents', ids: ['doc-1', 'doc-2'])
129
+
130
+ # By filter
131
+ client.delete(index: 'documents', filter: { category: 'old' })
132
+
133
+ # Delete all in namespace
134
+ client.delete(index: 'documents', delete_all: true)
135
+ ```
136
+
137
+ ### Index Management
138
+
139
+ ```ruby
140
+ # Create index
141
+ client.create_index(name: 'documents', dimension: 384, metric: 'cosine')
142
+
143
+ # List indexes
144
+ indexes = client.list_indexes
145
+ # => [{ name: 'documents', dimension: 384, ... }]
146
+
147
+ # Describe index
148
+ info = client.describe_index(index: 'documents')
149
+ # => { name: 'documents', dimension: 384, metric: 'cosine', status: 'ready' }
150
+
151
+ # Get stats
152
+ stats = client.stats(index: 'documents')
153
+ # => { total_vector_count: 1000, dimension: 384, namespaces: { ... } }
154
+
155
+ # List namespaces
156
+ namespaces = client.list_namespaces(index: 'documents')
157
+ # => ['tenant-1', 'tenant-2']
158
+
159
+ # Delete index
160
+ client.delete_index(name: 'old-index')
161
+ ```
162
+
163
+ **Note:** `create_index` and `delete_index` are supported by Pinecone, Qdrant, and pgvector. Memory and Weaviate providers don't support these operations.
164
+
165
+ ---
166
+
167
+ ## Health & Monitoring
168
+
169
+ ### Health Check
170
+
171
+ ```ruby
172
+ if client.healthy?
173
+ puts 'Vectra provider is healthy'
174
+ else
175
+ puts 'Vectra provider is NOT healthy'
176
+ end
177
+ ```
178
+
179
+ ### Ping (with latency)
180
+
181
+ ```ruby
182
+ status = client.ping
183
+ # => { healthy: true, provider: :qdrant, latency_ms: 23.4 }
184
+
185
+ puts "Provider: #{status[:provider]}, latency: #{status[:latency_ms]}ms"
186
+ ```
187
+
188
+ ### Rails Health Endpoint (Example)
189
+
190
+ ```ruby
191
+ # config/routes.rb
192
+ Rails.application.routes.draw do
193
+ get '/health/vectra', to: 'health#vectra'
194
+ end
195
+ ```
196
+
197
+ ```ruby
198
+ # app/controllers/health_controller.rb
199
+ class HealthController < ApplicationController
200
+ def vectra
201
+ client = Vectra::Client.new
202
+
203
+ status = client.ping
204
+ if status[:healthy]
205
+ render json: { status: 'ok', provider: status[:provider], latency_ms: status[:latency_ms] }
206
+ else
207
+ render json: { status: 'unhealthy' }, status: :service_unavailable
208
+ end
209
+ rescue => e
210
+ render json: { status: 'error', error: e.message }, status: :service_unavailable
211
+ end
212
+ end
213
+ ```
214
+
215
+ Use this endpoint for Kubernetes / load balancer health checks.
216
+
217
+ ---
218
+
219
+ ## Vector Helpers
220
+
221
+ ### Normalize Embeddings
222
+
223
+ ```ruby
224
+ embedding = openai_response['data'][0]['embedding']
225
+ normalized = Vectra::Vector.normalize(embedding, type: :l2) # or :l1
226
+
227
+ client.upsert(
228
+ index: 'documents',
229
+ vectors: [
230
+ { id: 'doc-1', values: normalized, metadata: { title: 'Hello' } }
231
+ ]
232
+ )
233
+ ```
234
+
235
+ ### In-Place Normalization
236
+
237
+ ```ruby
238
+ vector = Vectra::Vector.new(id: 'doc-1', values: embedding)
239
+ vector.normalize! # Mutates values
240
+ client.upsert(index: 'documents', vectors: [vector])
241
+ ```
242
+
243
+ ### Embedding Cache Helper
244
+
245
+ ```ruby
246
+ cache = Vectra::Cache.new(ttl: 600, max_size: 1000)
247
+
248
+ embedding = Vectra::Embeddings.fetch(
249
+ cache: cache,
250
+ model_name: "Product",
251
+ id: product.id,
252
+ input: product.description,
253
+ field: :description
254
+ ) do
255
+ EmbeddingService.generate(product.description)
256
+ end
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Batch Operations
262
+
263
+ ### Simple Batch Upsert
264
+
265
+ ```ruby
266
+ vectors = products.map do |product|
267
+ {
268
+ id: product.id.to_s,
269
+ values: product.embedding,
270
+ metadata: { name: product.name, price: product.price }
271
+ }
272
+ end
273
+
274
+ client.upsert(index: 'products', vectors: vectors)
275
+ ```
276
+
277
+ ### Batch with Progress Callback
278
+
279
+ ```ruby
280
+ Vectra::Batch.upsert(
281
+ client: client,
282
+ index: 'products',
283
+ vectors: vectors,
284
+ batch_size: 100,
285
+ on_progress: ->(batch_index, total_batches, batch_count) do
286
+ puts "Batch #{batch_index + 1}/#{total_batches} (#{batch_count} vectors)"
287
+ end
288
+ )
289
+ ```
290
+
291
+ ### Batch Query (Multiple Vectors)
292
+
293
+ ```ruby
294
+ batch = Vectra::Batch.new(client, concurrency: 4)
295
+
296
+ # Find similar items for multiple products at once
297
+ product_embeddings = products.map(&:embedding)
298
+ results = batch.query_async(
299
+ index: 'products',
300
+ vectors: product_embeddings,
301
+ top_k: 5
302
+ )
303
+
304
+ # Each result corresponds to one product
305
+ results.each_with_index do |result, i|
306
+ puts "Similar to product #{i}: #{result.ids}"
307
+ end
308
+ ```
309
+
310
+ ---
311
+
312
+ ## ActiveRecord + has_vector DSL
313
+
314
+ ### Basic Setup
315
+
316
+ ```ruby
317
+ class Document < ApplicationRecord
318
+ include Vectra::ActiveRecord
319
+
320
+ has_vector :embedding,
321
+ provider: :qdrant,
322
+ index: 'documents',
323
+ dimension: 1536,
324
+ metadata_fields: [:title, :category]
325
+ end
326
+ ```
327
+
328
+ ### Auto-Index on Save
329
+
330
+ ```ruby
331
+ doc = Document.create!(
332
+ title: 'Hello World',
333
+ category: 'docs',
334
+ embedding: EmbeddingService.generate('Hello World')
335
+ )
336
+ ```
337
+
338
+ ### Vector Search from Model
339
+
340
+ ```ruby
341
+ results = Document.vector_search(
342
+ embedding: EmbeddingService.generate('vector search in ruby'),
343
+ limit: 10,
344
+ filter: { category: 'docs' }
345
+ )
346
+
347
+ results.each do |doc|
348
+ puts doc.title
349
+ end
350
+ ```
351
+
352
+ ### Reindex All Records
353
+
354
+ ```ruby
355
+ # Reindex all documents that already have embeddings
356
+ processed = Document.reindex_vectors(
357
+ scope: Document.where.not(embedding: nil),
358
+ batch_size: 500
359
+ )
360
+
361
+ puts "Reindexed #{processed} documents"
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Error Handling
367
+
368
+ ```ruby
369
+ begin
370
+ client.query(index: 'missing', vector: [0.1, 0.2, 0.3])
371
+ rescue Vectra::NotFoundError => e
372
+ Rails.logger.warn("Index not found: #{e.message}")
373
+ rescue Vectra::RateLimitError => e
374
+ Rails.logger.error("Rate limited: #{e.message}")
375
+ rescue Vectra::Error => e
376
+ Rails.logger.error("Vectra error: #{e.message}")
377
+ end
378
+ ```
379
+
380
+ ---
381
+
382
+ ## See Also
383
+
384
+ - [API Overview](/api/overview/)
385
+ - [Recipes & Patterns](/guides/recipes/)
386
+ - [Rails Integration Guide](/guides/rails-integration/)
387
+ - [Memory Provider (Testing)](/providers/memory/)