mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-05-22 19:56:25 +00:00
docs: Add Cypher reference, include Tiny Dancer, fix WASM build
- Create docs/api/CYPHER_REFERENCE.md with complete Cypher query guide - Update README to highlight all capabilities in core npx ruvector package - Add Tiny Dancer (AI agent routing) to features and comparison table - Fix ruvector-wasm insertBatch to use js_sys::Array instead of serde
This commit is contained in:
parent
3972374eff
commit
ed2bdd014e
3 changed files with 254 additions and 8 deletions
21
README.md
21
README.md
|
|
@ -13,6 +13,8 @@
|
|||
npx ruvector
|
||||
```
|
||||
|
||||
> **All-in-One Package**: The core `ruvector` package includes everything — vector search, graph queries, GNN layers, tensor compression, and WASM support. No additional packages needed.
|
||||
|
||||
## What Problem Does RuVector Solve?
|
||||
|
||||
Traditional vector databases just store and search. When you ask "find similar items," they return results but never get smarter.
|
||||
|
|
@ -22,6 +24,8 @@ Traditional vector databases just store and search. When you ask "find similar i
|
|||
1. **Store vectors** like any vector DB (embeddings from OpenAI, Cohere, etc.)
|
||||
2. **Query with Cypher** like Neo4j (`MATCH (a)-[:SIMILAR]->(b) RETURN b`)
|
||||
3. **The index learns** — GNN layers make search results improve over time
|
||||
4. **Compress automatically** — 2-32x memory reduction with adaptive tiered compression
|
||||
5. **Run anywhere** — Node.js, browser (WASM), or native Rust
|
||||
|
||||
Think of it as: **Pinecone + Neo4j + PyTorch** in one Rust package.
|
||||
|
||||
|
|
@ -55,6 +59,10 @@ const enhanced = layer.forward(query, neighbors, weights);
|
|||
|
||||
// Compression (2-32x memory savings)
|
||||
const compressed = ruvector.compress(embedding, 0.3);
|
||||
|
||||
// Tiny Dancer: AI agent routing
|
||||
const router = new ruvector.Router();
|
||||
const decision = router.route(candidates, { optimize: 'cost' });
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
|
@ -90,6 +98,7 @@ let enhanced = layer.forward(&query, &neighbors, &weights);
|
|||
| **Hyperedges** | Connect 3+ nodes at once | Model complex relationships |
|
||||
| **Tensor Compression** | f32→f16→PQ8→PQ4→Binary | 2-32x memory reduction |
|
||||
| **Differentiable Search** | Soft attention k-NN | End-to-end trainable |
|
||||
| **Tiny Dancer** | FastGRNN neural routing | Optimize LLM inference costs |
|
||||
| **WASM/Browser** | Full client-side support | Run AI search offline |
|
||||
|
||||
## Comparison
|
||||
|
|
@ -101,6 +110,7 @@ let enhanced = layer.forward(&query, &neighbors, &weights);
|
|||
| **Graph Queries** | ✅ Cypher | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Hyperedges** | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Self-Learning (GNN)** | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **AI Agent Routing** | ✅ Tiny Dancer | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Auto-Compression** | ✅ 2-32x | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Browser/WASM** | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Differentiable** | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
|
|
@ -187,11 +197,12 @@ RETURN related
|
|||
|
||||
```
|
||||
crates/
|
||||
├── ruvector-core/ # Vector DB engine (HNSW, storage)
|
||||
├── ruvector-graph/ # Graph DB + Cypher parser
|
||||
├── ruvector-gnn/ # GNN layers, compression, training
|
||||
├── ruvector-gnn-wasm/ # WebAssembly bindings
|
||||
└── ruvector-gnn-node/ # Node.js bindings (napi-rs)
|
||||
├── ruvector-core/ # Vector DB engine (HNSW, storage)
|
||||
├── ruvector-graph/ # Graph DB + Cypher parser + Hyperedges
|
||||
├── ruvector-gnn/ # GNN layers, compression, training
|
||||
├── ruvector-tiny-dancer-core/ # AI agent routing (FastGRNN)
|
||||
├── ruvector-*-wasm/ # WebAssembly bindings
|
||||
└── ruvector-*-node/ # Node.js bindings (napi-rs)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
|
|
|||
|
|
@ -217,11 +217,13 @@ impl VectorDB {
|
|||
/// Array of vector IDs
|
||||
#[wasm_bindgen(js_name = insertBatch)]
|
||||
pub fn insert_batch(&self, entries: JsValue) -> Result<Vec<String>, JsValue> {
|
||||
let js_entries: Vec<JsValue> = from_value(entries)
|
||||
.map_err(|e| JsValue::from_str(&format!("Invalid entries array: {}", e)))?;
|
||||
// Convert JsValue to Array using reflection
|
||||
let entries_array: js_sys::Array = entries.dyn_into()
|
||||
.map_err(|_| JsValue::from_str("entries must be an array"))?;
|
||||
|
||||
let mut vector_entries = Vec::new();
|
||||
for js_entry in js_entries {
|
||||
for i in 0..entries_array.length() {
|
||||
let js_entry = entries_array.get(i);
|
||||
let vector_arr: Float32Array = Reflect::get(&js_entry, &"vector".into())?.dyn_into()?;
|
||||
let id: Option<String> = Reflect::get(&js_entry, &"id".into())?.as_string();
|
||||
let metadata = Reflect::get(&js_entry, &"metadata".into()).ok();
|
||||
|
|
|
|||
233
docs/api/CYPHER_REFERENCE.md
Normal file
233
docs/api/CYPHER_REFERENCE.md
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
# Cypher Query Language Reference
|
||||
|
||||
RuVector implements a Neo4j-compatible Cypher query language with extensions for hyperedges.
|
||||
|
||||
## Quick Examples
|
||||
|
||||
```cypher
|
||||
-- Create nodes
|
||||
CREATE (p:Person {name: 'Alice', age: 30})
|
||||
|
||||
-- Create relationships
|
||||
CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})
|
||||
|
||||
-- Pattern matching
|
||||
MATCH (p:Person)-[:KNOWS]->(friend)
|
||||
WHERE p.name = 'Alice'
|
||||
RETURN friend.name
|
||||
|
||||
-- Hyperedges (N-ary relationships)
|
||||
CREATE (a:Person)-[:ATTENDED]->(meeting:Meeting, room:Room, company:Company)
|
||||
```
|
||||
|
||||
## Supported Clauses
|
||||
|
||||
### MATCH
|
||||
|
||||
Find patterns in the graph.
|
||||
|
||||
```cypher
|
||||
-- Simple node
|
||||
MATCH (n:Person)
|
||||
RETURN n
|
||||
|
||||
-- With relationship
|
||||
MATCH (a:Person)-[:KNOWS]->(b:Person)
|
||||
RETURN a.name, b.name
|
||||
|
||||
-- Variable-length paths
|
||||
MATCH (a)-[*1..3]->(b)
|
||||
RETURN a, b
|
||||
|
||||
-- Optional matching
|
||||
OPTIONAL MATCH (p:Person)-[:OWNS]->(c:Car)
|
||||
RETURN p.name, c.model
|
||||
```
|
||||
|
||||
### CREATE
|
||||
|
||||
Create new nodes and relationships.
|
||||
|
||||
```cypher
|
||||
-- Single node
|
||||
CREATE (n:Person {name: 'Alice'})
|
||||
|
||||
-- Multiple labels
|
||||
CREATE (n:Person:Employee {name: 'Bob'})
|
||||
|
||||
-- With relationship
|
||||
CREATE (a:Person {name: 'Alice'})-[:FRIEND]->(b:Person {name: 'Bob'})
|
||||
```
|
||||
|
||||
### MERGE
|
||||
|
||||
Create if not exists, match if exists.
|
||||
|
||||
```cypher
|
||||
MERGE (p:Person {email: 'alice@example.com'})
|
||||
ON CREATE SET p.created = timestamp()
|
||||
ON MATCH SET p.lastSeen = timestamp()
|
||||
```
|
||||
|
||||
### SET
|
||||
|
||||
Update properties.
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person {name: 'Alice'})
|
||||
SET p.age = 31, p.updated = timestamp()
|
||||
```
|
||||
|
||||
### DELETE
|
||||
|
||||
Remove nodes and relationships.
|
||||
|
||||
```cypher
|
||||
-- Delete node (must have no relationships)
|
||||
MATCH (p:Person {name: 'Temp'})
|
||||
DELETE p
|
||||
|
||||
-- Delete node and all relationships
|
||||
MATCH (p:Person {name: 'Temp'})
|
||||
DETACH DELETE p
|
||||
```
|
||||
|
||||
### RETURN
|
||||
|
||||
Project results.
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person)
|
||||
RETURN p.name AS name, p.age
|
||||
ORDER BY p.age DESC
|
||||
SKIP 10
|
||||
LIMIT 5
|
||||
```
|
||||
|
||||
### WITH
|
||||
|
||||
Intermediate projection (query chaining).
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person)
|
||||
WITH p.name AS name, COUNT(*) AS count
|
||||
WHERE count > 1
|
||||
RETURN name, count
|
||||
```
|
||||
|
||||
### WHERE
|
||||
|
||||
Filter results.
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person)
|
||||
WHERE p.age > 21 AND p.city = 'NYC'
|
||||
RETURN p
|
||||
|
||||
-- Pattern predicates
|
||||
WHERE (p)-[:KNOWS]->(:Expert)
|
||||
```
|
||||
|
||||
## Hyperedges (N-ary Relationships)
|
||||
|
||||
RuVector extends Cypher with hyperedge support for N-ary relationships:
|
||||
|
||||
```cypher
|
||||
-- Create hyperedge (3+ nodes)
|
||||
CREATE (author:Person)-[:WROTE]->(paper:Paper, journal:Journal, year:Year)
|
||||
|
||||
-- Match hyperedge
|
||||
MATCH (a:Person)-[r:ATTENDED]->(meeting, room, company)
|
||||
RETURN a.name, meeting.topic, room.number
|
||||
```
|
||||
|
||||
## Expressions
|
||||
|
||||
### Operators
|
||||
|
||||
| Type | Operators |
|
||||
|------|-----------|
|
||||
| Arithmetic | `+`, `-`, `*`, `/`, `%`, `^` |
|
||||
| Comparison | `=`, `<>`, `<`, `>`, `<=`, `>=` |
|
||||
| Logical | `AND`, `OR`, `NOT`, `XOR` |
|
||||
| String | `STARTS WITH`, `ENDS WITH`, `CONTAINS` |
|
||||
| Null | `IS NULL`, `IS NOT NULL` |
|
||||
| List | `IN`, `[]` (indexing) |
|
||||
|
||||
### Functions
|
||||
|
||||
```cypher
|
||||
-- String
|
||||
RETURN toUpper(name), toLower(name), trim(name), substring(name, 0, 5)
|
||||
|
||||
-- Numeric
|
||||
RETURN abs(x), ceil(x), floor(x), round(x), sqrt(x)
|
||||
|
||||
-- Collections
|
||||
RETURN size(list), head(list), tail(list), range(1, 10)
|
||||
|
||||
-- Type
|
||||
RETURN type(r), labels(n), keys(n)
|
||||
```
|
||||
|
||||
### Aggregations
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person)
|
||||
RETURN
|
||||
COUNT(*) AS total,
|
||||
AVG(p.age) AS avgAge,
|
||||
MIN(p.age) AS minAge,
|
||||
MAX(p.age) AS maxAge,
|
||||
SUM(p.salary) AS totalSalary,
|
||||
COLLECT(p.name) AS names
|
||||
```
|
||||
|
||||
### CASE Expressions
|
||||
|
||||
```cypher
|
||||
MATCH (p:Person)
|
||||
RETURN p.name,
|
||||
CASE
|
||||
WHEN p.age < 18 THEN 'minor'
|
||||
WHEN p.age < 65 THEN 'adult'
|
||||
ELSE 'senior'
|
||||
END AS category
|
||||
```
|
||||
|
||||
## Data Types
|
||||
|
||||
| Type | Example |
|
||||
|------|---------|
|
||||
| Integer | `42`, `-17` |
|
||||
| Float | `3.14`, `-2.5e10` |
|
||||
| String | `'hello'`, `"world"` |
|
||||
| Boolean | `true`, `false` |
|
||||
| Null | `null` |
|
||||
| List | `[1, 2, 3]`, `['a', 'b']` |
|
||||
| Map | `{name: 'Alice', age: 30}` |
|
||||
|
||||
## Path Variables
|
||||
|
||||
```cypher
|
||||
-- Assign path to variable
|
||||
MATCH p = (a:Person)-[:KNOWS*]->(b:Person)
|
||||
RETURN p, length(p)
|
||||
|
||||
-- Path functions
|
||||
RETURN nodes(p), relationships(p), length(p)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use labels** - Always specify node labels for faster lookups
|
||||
2. **Index properties** - Create indexes on frequently queried properties
|
||||
3. **Limit results** - Use `LIMIT` to avoid large result sets
|
||||
4. **Parameterize** - Use parameters for values to enable query caching
|
||||
|
||||
## See Also
|
||||
|
||||
- [Getting Started Guide](../guide/GETTING_STARTED.md)
|
||||
- [Node.js API](./NODEJS_API.md)
|
||||
- [Rust API](./RUST_API.md)
|
||||
- [GNN Architecture](../gnn-layer-implementation.md)
|
||||
Loading…
Add table
Add a link
Reference in a new issue