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.
data/lib/vectra/client.rb CHANGED
@@ -36,10 +36,11 @@ module Vectra
36
36
  # environment: 'us-east-1'
37
37
  # )
38
38
  #
39
+ # rubocop:disable Metrics/ClassLength
39
40
  class Client
40
41
  include Vectra::HealthCheck
41
42
 
42
- attr_reader :config, :provider
43
+ attr_reader :config, :provider, :default_index, :default_namespace
43
44
 
44
45
  # Initialize a new Client
45
46
  #
@@ -48,17 +49,21 @@ module Vectra
48
49
  # @param environment [String, nil] environment/region
49
50
  # @param host [String, nil] custom host URL
50
51
  # @param options [Hash] additional options
52
+ # @option options [String] :index default index name
53
+ # @option options [String] :namespace default namespace
51
54
  def initialize(provider: nil, api_key: nil, environment: nil, host: nil, **options)
52
55
  @config = build_config(provider, api_key, environment, host, options)
53
56
  @config.validate!
54
57
  @provider = build_provider
58
+ @default_index = options[:index]
59
+ @default_namespace = options[:namespace]
55
60
  end
56
61
 
57
62
  # Upsert vectors into an index
58
63
  #
59
- # @param index [String] the index/collection name
60
64
  # @param vectors [Array<Hash, Vector>] vectors to upsert
61
- # @param namespace [String, nil] optional namespace (provider-specific)
65
+ # @param index [String, nil] the index/collection name (falls back to client's default)
66
+ # @param namespace [String, nil] optional namespace (provider-specific, falls back to client's default)
62
67
  # @return [Hash] upsert response with :upserted_count
63
68
  #
64
69
  # @example Upsert vectors
@@ -70,7 +75,9 @@ module Vectra
70
75
  # ]
71
76
  # )
72
77
  #
73
- def upsert(index:, vectors:, namespace: nil)
78
+ def upsert(vectors:, index: nil, namespace: nil)
79
+ index ||= default_index
80
+ namespace ||= default_namespace
74
81
  validate_index!(index)
75
82
  validate_vectors!(vectors)
76
83
 
@@ -129,6 +136,10 @@ module Vectra
129
136
  # Handle positional argument for index in non-builder case
130
137
  index = index_arg if index_arg && index.nil?
131
138
 
139
+ # Fall back to default index/namespace when not provided
140
+ index ||= default_index
141
+ namespace ||= default_namespace
142
+
132
143
  # Backwards-compatible path: perform query immediately
133
144
  validate_index!(index)
134
145
  validate_query_vector!(vector)
@@ -156,16 +167,18 @@ module Vectra
156
167
 
157
168
  # Fetch vectors by IDs
158
169
  #
159
- # @param index [String] the index/collection name
160
170
  # @param ids [Array<String>] vector IDs to fetch
161
- # @param namespace [String, nil] optional namespace
171
+ # @param index [String, nil] the index/collection name (falls back to client's default)
172
+ # @param namespace [String, nil] optional namespace (falls back to client's default)
162
173
  # @return [Hash<String, Vector>] hash of ID to Vector
163
174
  #
164
175
  # @example Fetch vectors
165
176
  # vectors = client.fetch(index: 'my-index', ids: ['vec1', 'vec2'])
166
177
  # vectors['vec1'].values # => [0.1, 0.2, 0.3]
167
178
  #
168
- def fetch(index:, ids:, namespace: nil)
179
+ def fetch(ids:, index: nil, namespace: nil)
180
+ index ||= default_index
181
+ namespace ||= default_namespace
169
182
  validate_index!(index)
170
183
  validate_ids!(ids)
171
184
 
@@ -181,8 +194,8 @@ module Vectra
181
194
 
182
195
  # Update a vector's metadata or values
183
196
  #
184
- # @param index [String] the index/collection name
185
197
  # @param id [String] vector ID
198
+ # @param index [String, nil] the index/collection name (falls back to client's default)
186
199
  # @param metadata [Hash, nil] new metadata (merged with existing)
187
200
  # @param values [Array<Float>, nil] new vector values
188
201
  # @param namespace [String, nil] optional namespace
@@ -195,7 +208,9 @@ module Vectra
195
208
  # metadata: { category: 'updated' }
196
209
  # )
197
210
  #
198
- def update(index:, id:, metadata: nil, values: nil, namespace: nil)
211
+ def update(id:, index: nil, metadata: nil, values: nil, namespace: nil)
212
+ index ||= default_index
213
+ namespace ||= default_namespace
199
214
  validate_index!(index)
200
215
  validate_id!(id)
201
216
 
@@ -235,7 +250,9 @@ module Vectra
235
250
  # @example Delete all
236
251
  # client.delete(index: 'my-index', delete_all: true)
237
252
  #
238
- def delete(index:, ids: nil, namespace: nil, filter: nil, delete_all: false)
253
+ def delete(index: nil, ids: nil, namespace: nil, filter: nil, delete_all: false)
254
+ index ||= default_index
255
+ namespace ||= default_namespace
239
256
  validate_index!(index)
240
257
 
241
258
  if ids.nil? && filter.nil? && !delete_all
@@ -279,7 +296,8 @@ module Vectra
279
296
  # info = client.describe_index(index: 'my-index')
280
297
  # puts info[:dimension]
281
298
  #
282
- def describe_index(index:)
299
+ def describe_index(index: nil)
300
+ index ||= default_index
283
301
  validate_index!(index)
284
302
  provider.describe_index(index: index)
285
303
  end
@@ -294,11 +312,80 @@ module Vectra
294
312
  # stats = client.stats(index: 'my-index')
295
313
  # puts "Total vectors: #{stats[:total_vector_count]}"
296
314
  #
297
- def stats(index:, namespace: nil)
315
+ def stats(index: nil, namespace: nil)
316
+ index ||= default_index
317
+ namespace ||= default_namespace
298
318
  validate_index!(index)
299
319
  provider.stats(index: index, namespace: namespace)
300
320
  end
301
321
 
322
+ # Create a new index
323
+ #
324
+ # @param name [String] the index name
325
+ # @param dimension [Integer] vector dimension
326
+ # @param metric [String] distance metric (default: "cosine")
327
+ # @param options [Hash] provider-specific options
328
+ # @return [Hash] index information
329
+ # @raise [NotImplementedError] if provider doesn't support index creation
330
+ #
331
+ # @example
332
+ # client.create_index(name: 'documents', dimension: 384, metric: 'cosine')
333
+ #
334
+ def create_index(name:, dimension:, metric: "cosine", **options)
335
+ unless provider.respond_to?(:create_index)
336
+ raise NotImplementedError, "Provider #{provider_name} does not support index creation"
337
+ end
338
+
339
+ Instrumentation.instrument(
340
+ operation: :create_index,
341
+ provider: provider_name,
342
+ index: name,
343
+ metadata: { dimension: dimension, metric: metric }
344
+ ) do
345
+ provider.create_index(name: name, dimension: dimension, metric: metric, **options)
346
+ end
347
+ end
348
+
349
+ # Delete an index
350
+ #
351
+ # @param name [String] the index name
352
+ # @return [Hash] delete response
353
+ # @raise [NotImplementedError] if provider doesn't support index deletion
354
+ #
355
+ # @example
356
+ # client.delete_index(name: 'documents')
357
+ #
358
+ def delete_index(name:)
359
+ unless provider.respond_to?(:delete_index)
360
+ raise NotImplementedError, "Provider #{provider_name} does not support index deletion"
361
+ end
362
+
363
+ Instrumentation.instrument(
364
+ operation: :delete_index,
365
+ provider: provider_name,
366
+ index: name
367
+ ) do
368
+ provider.delete_index(name: name)
369
+ end
370
+ end
371
+
372
+ # List all namespaces in an index
373
+ #
374
+ # @param index [String] the index name
375
+ # @return [Array<String>] list of namespace names
376
+ #
377
+ # @example
378
+ # namespaces = client.list_namespaces(index: 'documents')
379
+ # namespaces.each { |ns| puts "Namespace: #{ns}" }
380
+ #
381
+ def list_namespaces(index: nil)
382
+ index ||= default_index
383
+ validate_index!(index)
384
+ stats_data = provider.stats(index: index)
385
+ namespaces = stats_data[:namespaces] || {}
386
+ namespaces.keys.reject(&:empty?) # Exclude empty/default namespace
387
+ end
388
+
302
389
  # Hybrid search combining semantic (vector) and keyword (text) search
303
390
  #
304
391
  # Combines the best of both worlds: semantic understanding from vectors
@@ -341,6 +428,8 @@ module Vectra
341
428
  #
342
429
  def hybrid_search(index:, vector:, text:, alpha: 0.5, top_k: 10, namespace: nil,
343
430
  filter: nil, include_values: false, include_metadata: true)
431
+ index ||= default_index
432
+ namespace ||= default_namespace
344
433
  validate_index!(index)
345
434
  validate_query_vector!(vector)
346
435
  raise ValidationError, "Text query cannot be nil or empty" if text.nil? || text.empty?
@@ -604,5 +693,48 @@ module Vectra
604
693
  config.logger.debug("[Vectra] #{message}")
605
694
  config.logger.debug("[Vectra] #{data.inspect}") if data
606
695
  end
696
+
697
+ # Temporarily override default index within a block.
698
+ #
699
+ # @param index [String] temporary index name
700
+ # @yield [Client] yields self with overridden index
701
+ # @return [Object] block result
702
+ def with_index(index)
703
+ previous = @default_index
704
+ @default_index = index
705
+ yield self
706
+ ensure
707
+ @default_index = previous
708
+ end
709
+
710
+ # Temporarily override default namespace within a block.
711
+ #
712
+ # @param namespace [String] temporary namespace
713
+ # @yield [Client] yields self with overridden namespace
714
+ # @return [Object] block result
715
+ def with_namespace(namespace)
716
+ previous = @default_namespace
717
+ @default_namespace = namespace
718
+ yield self
719
+ ensure
720
+ @default_namespace = previous
721
+ end
722
+
723
+ # Temporarily override both index and namespace within a block.
724
+ #
725
+ # @param index [String] temporary index name
726
+ # @param namespace [String] temporary namespace
727
+ # @yield [Client] yields self with overridden index and namespace
728
+ # @return [Object] block result
729
+ def with_index_and_namespace(index, namespace)
730
+ with_index(index) do
731
+ with_namespace(namespace) do
732
+ yield self
733
+ end
734
+ end
735
+ end
736
+
737
+ public :with_index, :with_namespace, :with_index_and_namespace
607
738
  end
739
+ # rubocop:enable Metrics/ClassLength
608
740
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vectra
4
- VERSION = "1.0.6"
4
+ VERSION = "1.0.8"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vectra-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.6
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mijo Kristo
@@ -251,6 +251,8 @@ files:
251
251
  - docs/_site/providers/weaviate/index.html
252
252
  - docs/_site/robots.txt
253
253
  - docs/_site/sitemap.xml
254
+ - docs/api/cheatsheet.md
255
+ - docs/api/methods.md
254
256
  - docs/api/overview.md
255
257
  - docs/assets/favicon.svg
256
258
  - docs/assets/logo.svg
@@ -263,23 +265,27 @@ files:
263
265
  - docs/examples/index.md
264
266
  - docs/examples/real-world.md
265
267
  - docs/grafana_final.png
268
+ - docs/guides/faq.md
266
269
  - docs/guides/getting-started.md
267
270
  - docs/guides/installation.md
268
271
  - docs/guides/monitoring.md
269
272
  - docs/guides/performance.md
270
273
  - docs/guides/rails-integration.md
271
274
  - docs/guides/rails-troubleshooting.md
275
+ - docs/guides/recipes.md
272
276
  - docs/guides/runbooks/cache-issues.md
273
277
  - docs/guides/runbooks/high-error-rate.md
274
278
  - docs/guides/runbooks/high-latency.md
275
279
  - docs/guides/runbooks/pool-exhausted.md
276
280
  - docs/guides/security.md
281
+ - docs/guides/testing.md
277
282
  - docs/index.md
278
283
  - docs/providers/index.md
279
284
  - docs/providers/memory.md
280
285
  - docs/providers/pgvector.md
281
286
  - docs/providers/pinecone.md
282
287
  - docs/providers/qdrant.md
288
+ - docs/providers/selection.md
283
289
  - docs/providers/weaviate.md
284
290
  - examples/GRAFANA_QUICKSTART.md
285
291
  - examples/README.md