123456789_123456789_123456789_123456789_123456789_

Module: Redis::Commands::VectorSets

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: lib/redis/commands/vector_sets.rb

Instance Method Summary

Instance Method Details

#vadd(key, vector, element, reduce: nil, cas: nil, quantization: nil, ef: nil, attributes: nil, m: nil) ⇒ Boolean

Add a new element into a vector set, or update its vector if it already exists.

The vector can be given as an Array of numbers (sent as VALUES), or as a String holding a little-endian FP32 blob (sent as FP32), e.g. values.pack("e*").

Examples:

Add an element with an array of values

redis.vadd("mykey", [0.1, 1.2, 0.5], "my-element")
  # => true

Add an element with an FP32 blob

redis.vadd("mykey", [0.1, 1.2, 0.5].pack("e*"), "my-element")
  # => true

Reduce dimensionality and attach attributes

redis.vadd("mykey", [0.1, 1.2, 0.5], "my-element", reduce: 2, attributes: { size: "large" })
  # => true

Parameters:

  • key (String)
  • vector (Array<Numeric>, String)

    the vector as an array of numbers, or a little-endian FP32 blob

  • element (String)

    name of the element being added

  • options (Hash)

Returns:

  • (Boolean)

    whether the element was added

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 42

def vadd(key, vector, element, reduce: nil, cas: nil, quantization: nil, ef: nil, attributes: nil, m: nil)
  args = [:vadd, key]
  args << "REDUCE" << Integer(reduce) if reduce

  if vector.is_a?(String)
    args << "FP32" << vector
  else
    args << "VALUES" << vector.size
    args.concat(vector.map { |value| Float(value) })
  end

  args << element
  args << "CAS" if cas

  if quantization
    case quantization.to_s.downcase
    when "noquant" then args << "NOQUANT"
    when "q8" then args << "Q8"
    when "bin" then args << "BIN"
    else raise ArgumentError, "unknown quantization: #{quantization.inspect}"
    end
  end

  args << "EF" << Integer(ef) if ef

  if attributes
    args << "SETATTR" << (attributes.is_a?(String) ? attributes : ::JSON.generate(attributes))
  end

  args << "M" << Integer(m) if m

  send_command(args, &BoolifyBoolean)
end

#vcard(key) ⇒ Integer

Return the number of elements in a vector set.

Examples:

redis.vcard("mykey")
  # => 2

Parameters:

  • key (String)

Returns:

  • (Integer)

    the number of elements in the vector set, or 0 if the key does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 85

def vcard(key)
  send_command([:vcard, key])
end

#vdim(key) ⇒ Integer

Return the number of dimensions of the vectors in a vector set.

For a vector set created with the REDUCE option this reports the reduced dimension, although full-size vectors must still be used when querying with VSIM.

Examples:

redis.vdim("mykey")
  # => 3

Parameters:

  • key (String)

Returns:

  • (Integer)

    the dimension of the vectors in the set

Raises:

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 102

def vdim(key)
  send_command([:vdim, key])
end

#vemb(key, element, raw: nil) ⇒ Array<Float>, ...

Return the approximate vector associated with an element in a vector set. The round trip is approximate because vectors are normalized and (by default) quantized on insertion.

Examples:

redis.vemb("mykey", "my-element")
  # => [0.1004752591252327, 1.2000000476837158, 0.5023762512207031]

Raw internal representation

redis.vemb("mykey", "my-element", raw: true)
  # => { "quantization" => "int8", "raw" => "\x0b\x7f5", "l2" => 1.3038404, "range" => 0.009448819 }

Parameters:

  • key (String)
  • element (String)

    name of the element whose vector to retrieve

  • raw (Boolean)

    return the raw internal representation instead

Returns:

  • (Array<Float>, Hash, nil)

    the vector as an array of Floats; with raw: true a Hash with "quantization", "raw" (blob), "l2" and, for q8 sets, "range" keys; nil if the key or element does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 123

def vemb(key, element, raw: nil)
  if raw
    send_command([:vemb, key, element, "RAW"], &HashifyVectorEmbeddingRaw)
  else
    send_command([:vemb, key, element], &FloatifyArray)
  end
end

#vgetattr(key, element, raw: false) ⇒ Object, ...

Return the JSON attributes associated with an element in a vector set.

By default the reply is parsed with JSON.parse; pass raw: true to get the JSON string as stored.

Examples:

redis.vgetattr("mykey", "my-element")
  # => { "size" => "large" }

Raw JSON string

redis.vgetattr("mykey", "my-element", raw: true)
  # => "{\"size\": \"large\"}"

Parameters:

  • key (String)
  • element (String)

    name of the element whose attributes to retrieve

  • raw (Boolean)

    return the JSON string without parsing it

Returns:

  • (Object, String, nil)

    the parsed attributes (or the JSON string with raw: true); nil if the key or element does not exist or has no attributes

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 396

def vgetattr(key, element, raw: false)
  send_command([:vgetattr, key, element]) do |reply|
    if reply.nil? || raw
      reply
    else
      ::JSON.parse(reply)
    end
  end
end

#vinfo(key) ⇒ Hash?

Return metadata and internal details about a vector set, including size, dimensions, quantization type, and graph structure.

Examples:

redis.vinfo("mykey")
  # => { "quant-type" => "int8", "vector-dim" => 3, "size" => 1, ... }

Parameters:

  • key (String)

Returns:

  • (Hash, nil)

    the vector set metadata, or nil if the key does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 347

def vinfo(key)
  send_command([:vinfo, key], &Hashify)
end

#vismember(key, element) ⇒ Boolean

Check if an element exists in a vector set.

Examples:

redis.vismember("mykey", "my-element")
  # => true

Parameters:

  • key (String)
  • element (String)

    name of the element to check for membership

Returns:

  • (Boolean)

    whether the element exists in the vector set; false if the key does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 274

def vismember(key, element)
  send_command([:vismember, key, element], &BoolifyBoolean)
end

#vrandmember(key, count = nil) ⇒ String, ...

Return one or more random elements from a vector set.

Behaves like SRANDMEMBER: a positive count returns up to that many distinct elements, a negative count returns exactly that many elements possibly with duplicates, and a count exceeding the set size returns the whole set.

Examples:

redis.vrandmember("mykey")
  # => "elem-2"

With a count

redis.vrandmember("mykey", 2)
  # => ["elem-1", "elem-3"]

Parameters:

  • key (String)
  • count (Integer) (defaults to: nil)

    number of elements to return; positive for distinct elements, negative to allow duplicates

Returns:

  • (String, Array<String>, nil)

    a single element (or nil for a missing key) without count; an array of elements (empty for a missing key) with count

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 298

def vrandmember(key, count = nil)
  if count.nil?
    send_command([:vrandmember, key])
  else
    send_command([:vrandmember, key, Integer(count)])
  end
end

#vrange(key, start, stop, count = nil) ⇒ Array<String>

Return the elements of a vector set within a lexicographical range, in lexicographical (byte-by-byte) order.

Boundaries follow the ZRANGEBYLEX syntax: "[elem" inclusive, "(elem" exclusive, "-" minimum, "+" maximum. A negative count returns all elements in the range. VRANGE is a stateless iterator: to paginate, pass the last returned element as an exclusive start on the next call.

Examples:

All elements

redis.vrange("mykey", "-", "+")
  # => ["elem-1", "elem-2", "elem-3"]

Paginate, two at a time

redis.vrange("mykey", "-", "+", 2)
  # => ["elem-1", "elem-2"]
redis.vrange("mykey", "(elem-2", "+", 2)
  # => ["elem-3"]

Parameters:

  • key (String)
  • start (String)

    range start: "[elem", "(elem" or "-"

  • stop (String)

    range end: "[elem", "(elem" or "+"

  • count (Integer) (defaults to: nil)

    maximum number of elements to return; negative returns the whole range

Returns:

  • (Array<String>)

    the elements in the range, empty if the key does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 331

def vrange(key, start, stop, count = nil)
  args = [:vrange, key, start, stop]
  args << Integer(count) if count
  send_command(args)
end

#vrem(key, element) ⇒ Boolean

Remove an element from a vector set. Memory is reclaimed immediately.

Examples:

redis.vrem("mykey", "my-element")
  # => true

Parameters:

  • key (String)
  • element (String)

    name of the element to remove

Returns:

  • (Boolean)

    whether the element was removed; false if the key or element does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 260

def vrem(key, element)
  send_command([:vrem, key, element], &BoolifyBoolean)
end

#vsetattr(key, element, attributes) ⇒ Boolean

Associate JSON attributes with an element in a vector set, update them, or delete them. Attributes can be used in filtered similarity searches with VSIM.

Examples:

Set attributes from a Hash

redis.vsetattr("mykey", "my-element", { type: "fruit", color: "red" })
  # => true

Delete the attributes

redis.vsetattr("mykey", "my-element", nil)
  # => true

Parameters:

  • key (String)
  • element (String)

    name of the element whose attributes to set

  • attributes (Hash, String, nil)

    attributes as an object serialized to JSON or a pre-encoded JSON string; nil or an empty string deletes the attributes

Returns:

  • (Boolean)

    whether the attributes were set; false if the key or element does not exist

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 369

def vsetattr(key, element, attributes)
  json = case attributes
  when nil then ""
  when String then attributes
  else ::JSON.generate(attributes)
  end
  send_command([:vsetattr, key, element, json], &BoolifyBoolean)
end

#vsim(key, vector: nil, element: nil, withscores: false, with_scores: withscores, withattribs: false, with_attribs: withattribs, raw: false, count: nil, epsilon: nil, ef: nil, filter: nil, filter_ef: nil, truth: nil, nothread: nil) ⇒ Array<String>, Hash

Return elements similar to a given vector or element, by approximate (HNSW) or exact (truth: true) similarity search.

The query is either a vector — an Array of numbers (sent as VALUES) or a little-endian FP32 String blob (sent as FP32) — or the name of an existing element (sent as ELE). Exactly one of vector: and element: must be given.

Examples:

Query by element

redis.vsim("mykey", element: "apple", count: 3)
  # => ["apple", "apples", "pear"]

Query by vector, with similarity scores

redis.vsim("mykey", vector: [0.1, 1.2, 0.5], with_scores: true)
  # => { "apple" => 0.9998867657923256, ... }

With scores and attributes

redis.vsim("mykey", element: "apple", with_scores: true, with_attribs: true)
  # => { "apple" => [0.9998867657923256, { "len" => 5 }], ... }

Parameters:

  • key (String)
  • options (Hash)

Returns:

  • (Array<String>, Hash)

    element names; with with_scores: a { name => Float } Hash; with with_scores: and with_attribs: a { name => [Float, Object] } Hash; with with_attribs: alone a { name => Object } Hash (the attributes as JSON strings when raw: true). Empty when the key does not exist.

Raises:

[ GitHub ]

  
# File 'lib/redis/commands/vector_sets.rb', line 199

def vsim(key, vector: nil, element: nil, withscores: false, with_scores: withscores,
         withattribs: false, with_attribs: withattribs, raw: false, count: nil,
         epsilon: nil, ef: nil, filter: nil, filter_ef: nil, truth: nil, nothread: nil)
  unless vector.nil? ^ element.nil?
    raise ArgumentError, "must provide exactly one of vector or element"
  end

  args = [:vsim, key]
  if element
    args << "ELE" << element
  elsif vector.is_a?(String)
    args << "FP32" << vector
  else
    args << "VALUES" << vector.size
    args.concat(vector.map { |value| Float(value) })
  end
  args << "WITHSCORES" if with_scores
  args << "WITHATTRIBS" if with_attribs
  args << "COUNT" << Integer(count) if count
  args << "EPSILON" << Float(epsilon) if epsilon
  args << "EF" << Integer(ef) if ef
  args << "FILTER" << filter if filter
  args << "FILTER-EF" << Integer(filter_ef) if filter_ef
  args << "TRUTH" if truth
  args << "NOTHREAD" if nothread

  if with_scores && with_attribs
    send_command(args) do |reply|
      reply = HashifyVectorScoresWithAttribs.call(reply)
      if raw || !reply.is_a?(Hash)
        reply
      else
        reply.transform_values { |(score, attribs)| [score, attribs && ::JSON.parse(attribs)] }
      end
    end
  elsif with_scores
    send_command(args, &HashifyVectorScores)
  elsif with_attribs
    send_command(args) do |reply|
      reply = Hashify.call(reply)
      if raw || !reply.is_a?(Hash)
        reply
      else
        reply.transform_values { |attribs| attribs && ::JSON.parse(attribs) }
      end
    end
  else
    send_command(args)
  end
end