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 +4 -4
- data/CHANGELOG.md +8 -5
- data/README.md +13 -0
- data/docs/_layouts/default.html +1 -0
- data/docs/_layouts/home.html +45 -0
- data/docs/_layouts/page.html +1 -0
- data/docs/api/cheatsheet.md +387 -0
- data/docs/api/methods.md +632 -0
- data/docs/api/overview.md +1 -1
- data/docs/assets/style.css +50 -1
- data/docs/examples/index.md +0 -1
- data/docs/guides/faq.md +215 -0
- data/docs/guides/recipes.md +612 -0
- data/docs/guides/testing.md +211 -0
- data/docs/providers/selection.md +215 -0
- data/lib/vectra/active_record.rb +52 -1
- data/lib/vectra/batch.rb +69 -0
- data/lib/vectra/cache.rb +49 -0
- data/lib/vectra/client.rb +144 -12
- data/lib/vectra/version.rb +1 -1
- metadata +7 -1
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
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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
|
data/lib/vectra/version.rb
CHANGED
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.
|
|
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
|