ruvector/examples/graph_wasm_usage.html
Claude f3f7a95752 feat: Add Neo4j-compatible hypergraph database package (ruvector-graph)
Major new package implementing a distributed hypergraph database with:

## Core Components (crates/ruvector-graph/)
- Cypher-compatible query parser with lexer, AST, optimizer
- Query execution engine with SIMD optimization and parallel execution
- ACID transaction support with MVCC isolation levels
- Distributed consensus and federation layer
- Vector-graph hybrid queries for AI/RAG workloads
- Performance optimizations (100x faster than Neo4j target)

## Bindings
- WASM bindings (crates/ruvector-graph-wasm/)
- NAPI-RS Node.js bindings (crates/ruvector-graph-node/)
- NPM packages for both targets

## CLI Integration
- 8 new graph commands: create, query, shell, import, export, info, benchmark, serve

## CI/CD
- Updated build-native.yml for graph packages
- New graph-ci.yml for testing and benchmarks
- New graph-release.yml for automated publishing

## Data Generation
- OpenRouter/Kimi K2 integration (packages/graph-data-generator/)
- Agentic-synth benchmark suite integration

## Tests & Benchmarks
- 11 test files covering all components
- Criterion benchmarks for performance validation
- Neo4j compatibility test suite

## Architecture Highlights
- CSR graph layout for cache-friendly access
- SIMD-vectorized query operators
- Roaring bitmaps for label indexes
- Bloom filters for fast negative lookups
- Adaptive radix tree for property indexes

Note: This is a comprehensive implementation created by 15 parallel agents.
Some integration fixes may be needed to resolve cross-module dependencies.

Co-authored-by: Claude AI Swarm <swarm@claude.ai>
2025-11-25 23:11:54 +00:00

361 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RuVector Graph WASM Demo</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: #f5f5f5;
}
.container {
background: white;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
border-bottom: 3px solid #4CAF50;
padding-bottom: 10px;
}
.demo-section {
margin: 30px 0;
padding: 20px;
background: #f9f9f9;
border-radius: 6px;
border-left: 4px solid #4CAF50;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 12px 24px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin: 5px;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.output {
background: #2d2d2d;
color: #f8f8f2;
padding: 15px;
border-radius: 4px;
margin-top: 15px;
font-family: 'Courier New', monospace;
font-size: 13px;
max-height: 400px;
overflow-y: auto;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.stat-card {
background: white;
padding: 15px;
border-radius: 6px;
border: 1px solid #ddd;
text-align: center;
}
.stat-value {
font-size: 32px;
font-weight: bold;
color: #4CAF50;
}
.stat-label {
font-size: 14px;
color: #666;
margin-top: 5px;
}
.loading {
text-align: center;
padding: 40px;
color: #666;
}
.error {
background: #ffebee;
color: #c62828;
padding: 15px;
border-radius: 4px;
margin: 15px 0;
border-left: 4px solid #c62828;
}
</style>
</head>
<body>
<div class="container">
<h1>🔗 RuVector Graph WASM Demo</h1>
<div id="loading" class="loading">
<p>Loading WebAssembly module...</p>
</div>
<div id="error" style="display: none;" class="error"></div>
<div id="content" style="display: none;">
<div class="demo-section">
<h2>Database Operations</h2>
<button onclick="createSampleGraph()">Create Sample Graph</button>
<button onclick="createHypergraph()">Create Hypergraph</button>
<button onclick="queryGraph()">Query Nodes</button>
<button onclick="exportCypher()">Export as Cypher</button>
<button onclick="clearDatabase()">Clear Database</button>
</div>
<div class="demo-section">
<h2>Statistics</h2>
<div class="stats" id="stats">
<div class="stat-card">
<div class="stat-value" id="nodeCount">0</div>
<div class="stat-label">Nodes</div>
</div>
<div class="stat-card">
<div class="stat-value" id="edgeCount">0</div>
<div class="stat-label">Edges</div>
</div>
<div class="stat-card">
<div class="stat-value" id="hyperedgeCount">0</div>
<div class="stat-label">Hyperedges</div>
</div>
<div class="stat-card">
<div class="stat-value" id="avgDegree">0.0</div>
<div class="stat-label">Avg Degree</div>
</div>
</div>
</div>
<div class="demo-section">
<h2>Console Output</h2>
<div class="output" id="output">Ready to execute operations...</div>
</div>
</div>
</div>
<script type="module">
import init, { GraphDB } from '../npm/packages/graph-wasm/ruvector_graph_wasm.js';
let db;
async function initWasm() {
try {
await init();
db = new GraphDB('cosine');
document.getElementById('loading').style.display = 'none';
document.getElementById('content').style.display = 'block';
log('✅ WASM module loaded successfully');
log('✅ GraphDB initialized with cosine distance metric');
updateStats();
} catch (error) {
showError('Failed to initialize WASM: ' + error.message);
}
}
window.createSampleGraph = function() {
try {
log('Creating sample social network graph...');
// Create people
const alice = db.createNode(['Person'], {
name: 'Alice',
age: 30,
city: 'New York'
});
log(`Created node: Alice (${alice})`);
const bob = db.createNode(['Person'], {
name: 'Bob',
age: 35,
city: 'San Francisco'
});
log(`Created node: Bob (${bob})`);
const charlie = db.createNode(['Person'], {
name: 'Charlie',
age: 28,
city: 'New York'
});
log(`Created node: Charlie (${charlie})`);
// Create company
const company = db.createNode(['Company'], {
name: 'TechCorp',
founded: 2010
});
log(`Created node: TechCorp (${company})`);
// Create relationships
const friendship1 = db.createEdge(alice, bob, 'KNOWS', {
since: 2015,
strength: 0.9
});
log(`Created edge: Alice KNOWS Bob`);
const friendship2 = db.createEdge(bob, charlie, 'KNOWS', {
since: 2018,
strength: 0.7
});
log(`Created edge: Bob KNOWS Charlie`);
const works1 = db.createEdge(alice, company, 'WORKS_AT', {
since: 2020,
position: 'Engineer'
});
log(`Created edge: Alice WORKS_AT TechCorp`);
const works2 = db.createEdge(charlie, company, 'WORKS_AT', {
since: 2019,
position: 'Designer'
});
log(`Created edge: Charlie WORKS_AT TechCorp`);
log('✅ Sample graph created successfully!');
updateStats();
} catch (error) {
showError('Error creating graph: ' + error.message);
}
};
window.createHypergraph = function() {
try {
log('Creating hypergraph example...');
// Create documents with embeddings
const doc1 = db.createNode(['Document'], {
title: 'AI Research Paper',
embedding: generateRandomEmbedding(384)
});
log(`Created document node: ${doc1}`);
const doc2 = db.createNode(['Document'], {
title: 'ML Tutorial',
embedding: generateRandomEmbedding(384)
});
log(`Created document node: ${doc2}`);
const author = db.createNode(['Person'], {
name: 'Dr. Smith',
embedding: generateRandomEmbedding(384)
});
log(`Created author node: ${author}`);
// Create hyperedge connecting all three
const hyperedge = db.createHyperedge(
[doc1, doc2, author],
'Research papers authored by Dr. Smith on related AI topics',
null, // Auto-generate embedding
0.95
);
log(`Created hyperedge: ${hyperedge}`);
const he = db.getHyperedge(hyperedge);
log(`Hyperedge order (connected nodes): ${he.order}`);
log(`Hyperedge confidence: ${he.confidence}`);
log('✅ Hypergraph created successfully!');
updateStats();
} catch (error) {
showError('Error creating hypergraph: ' + error.message);
}
};
window.queryGraph = async function() {
try {
log('Querying graph for Person nodes...');
// Note: Full Cypher support is limited in this version
// This demonstrates the API even if query parsing is basic
const results = await db.query('MATCH (n:Person) RETURN n');
log(`Query returned ${results.count} results`);
log(`Nodes: ${results.nodes.length}`);
log(`Edges: ${results.edges.length}`);
log(`Hyperedges: ${results.hyperedges.length}`);
if (results.isEmpty()) {
log('No results found. Try creating a sample graph first.');
} else {
log('✅ Query executed successfully!');
}
updateStats();
} catch (error) {
showError('Error querying graph: ' + error.message);
}
};
window.exportCypher = function() {
try {
log('Exporting database as Cypher...');
const cypher = db.exportCypher();
if (cypher.trim() === '') {
log('Database is empty. Nothing to export.');
} else {
log('Exported Cypher statements:');
log('');
log(cypher);
log('✅ Export complete!');
}
} catch (error) {
showError('Error exporting: ' + error.message);
}
};
window.clearDatabase = function() {
try {
log('Clearing database...');
db = new GraphDB('cosine');
log('✅ Database cleared!');
updateStats();
} catch (error) {
showError('Error clearing database: ' + error.message);
}
};
function updateStats() {
try {
const stats = db.stats();
document.getElementById('nodeCount').textContent = stats.nodeCount;
document.getElementById('edgeCount').textContent = stats.edgeCount;
document.getElementById('hyperedgeCount').textContent = stats.hyperedgeCount;
document.getElementById('avgDegree').textContent = stats.avgEntityDegree.toFixed(2);
} catch (error) {
console.error('Error updating stats:', error);
}
}
function log(message) {
const output = document.getElementById('output');
const timestamp = new Date().toLocaleTimeString();
output.innerHTML += `[${timestamp}] ${message}\n`;
output.scrollTop = output.scrollHeight;
}
function showError(message) {
const errorDiv = document.getElementById('error');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
log('❌ ERROR: ' + message);
}
function generateRandomEmbedding(dim) {
return Array.from({ length: dim }, () => Math.random() * 2 - 1);
}
// Initialize on page load
initWasm();
</script>
</body>
</html>