zvec-ruby
Ruby bindings for zvec, a high-performance C++ vector database from Alibaba. Built with Rice (Ruby's C++ binding library).
Installation
# Gemfile
gem "zvec-ruby"Precompiled platform support
Starting with v0.2.1, precompiled native gems are published for supported platforms. No C++ toolchain is required on those platforms.
| Platform | Ruby versions | Notes |
|---|---|---|
x86_64-linux |
3.1, 3.2, 3.3, 3.4 | Built via rake-compiler-dock
|
aarch64-linux |
3.1, 3.2, 3.3, 3.4 | Built via rake-compiler-dock
|
arm64-darwin |
3.3 only | Built on macOS runner |
x86_64-darwin |
3.3 only | Built on macOS runner |
On any other platform, or on Darwin with a Ruby version other than 3.3, Bundler falls back to the source gem. Building from source requires CMake, a C++17 compiler, and the pinned upstream zvec C++ library. Use script/build_zvec.sh to build zvec, then set ZVEC_DIR before installing:
./script/build_zvec.sh
ZVEC_DIR=/tmp/zvec bundle install && bundle exec rake compileQuick Start
require "zvec"
# Define a schema
schema = Zvec::Schema.new("my_collection") do
string "title"
int32 "year"
vector "embedding", dimension: 128,
index: Zvec::Ext::HnswIndexParams.new(Zvec::COSINE)
end
# Create and populate a collection
collection = Zvec::Collection.create_and_open("/tmp/my_vectors", schema)
collection.add(pk: "doc1", title: "Hello", year: 2025,
embedding: Array.new(128) { rand })
# Search
results = collection.search([0.1] * 128, top_k: 5)
results.each { |doc| puts "#{doc.pk}: #{doc.score}" }
# Clean up
collection.destroySchema DSL
schema = Zvec::Schema.new("name") do
string "title"
int32 "count"
int64 "big_count"
float "score"
double "precise_score"
bool "active"
vector "embedding", dimension: 1536
field "tags", Zvec::ARRAY_STRING
endIndex Types
# HNSW (default for vector search)
Zvec::Ext::HnswIndexParams.new(Zvec::COSINE, m: 16, ef_construction: 200)
# Flat (brute-force, exact)
Zvec::Ext::FlatIndexParams.new(Zvec::L2)
# IVF (inverted file index)
Zvec::Ext::IVFIndexParams.new(Zvec::IP, n_list: 1024)
# Inverted index (for scalar fields)
Zvec::Ext::InvertIndexParams.newCollection API
# CRUD
collection.add(pk: "id", title: "text", embedding: [...])
collection.upsert(doc)
collection.delete("id1", "id2")
collection.fetch("id1")
# Search
collection.search(vector, top_k: 10, filter: "year > 2024")
# Full query control
collection.query(
field_name: "embedding",
vector: [...],
topk: 10,
filter: "category='tech'",
include_vector: true,
output_fields: ["title", "url"]
)
# Management
collection.flush
collection.optimize
collection.doc_count
collection.destroyruby_llm Integration
require "zvec/ruby_llm"
store = Zvec::RubyLLM::Store.new("/tmp/vectors", dimension: 1536, metric: :cosine)
store.add("doc-1", embedding: [...], content: "Some text")
store.search(query_embedding, top_k: 5)ActiveRecord Integration
require "zvec/active_record"
class Article < ApplicationRecord
include Zvec::ActiveRecord::Vectorize
vectorize :content,
dimensions: 1536,
embed_with: ->(text) { MyEmbedder.embed(text) }
end
# Automatic embedding on save
article = Article.create!(title: "Hello", content: "World")
# Vector similarity search
Article.vector_search("similar articles", top_k: 5)
Article.vector_search([0.1, 0.2, ...], top_k: 10, embed: false)Development
# Build zvec
./script/build_zvec.sh
# Compile and test
ZVEC_DIR=/tmp/zvec bundle exec rake compile
ZVEC_DIR=/tmp/zvec bundle exec rake test
# Run pure Ruby tests only (no native extension needed)
bundle exec rake test_pure
# Package a native gem for your platform
ruby script/package_native_gem.rbLicense
Apache-2.0 (same as zvec)