Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
543 changes: 354 additions & 189 deletions docker-compose.arm64.yml

Large diffs are not rendered by default.

312 changes: 312 additions & 0 deletions nornicdb/docs/EXECUTOR_MODES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
# Cypher Executor Modes: Architecture Overview

> **Environment Variable:** `NORNICDB_EXECUTOR_MODE`
> **Options:** `nornic` | `antlr` | `hybrid` (default)

## Architecture Diagram

```mermaid
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1f6feb', 'primaryTextColor': '#c9d1d9', 'primaryBorderColor': '#30363d', 'lineColor': '#8b949e', 'secondaryColor': '#238636', 'tertiaryColor': '#21262d', 'background': '#0d1117', 'mainBkg': '#161b22', 'textColor': '#c9d1d9'}}}%%

flowchart TB
subgraph ENV["πŸ”§ Configuration"]
direction LR
E1["NORNICDB_EXECUTOR_MODE"]
E2["nornic | antlr | hybrid"]
end

Q[/"Cypher Query"/]

Q --> FACTORY["NewCypherExecutor()"]

FACTORY --> |"mode=nornic"| NORNIC
FACTORY --> |"mode=antlr"| ANTLR
FACTORY --> |"mode=hybrid"| HYBRID

subgraph NORNIC["⚑ Nornic Mode"]
direction TB
N1["String Parser"]
N2["Regex + indexOf"]
N3["Direct Execution"]
N1 --> N2 --> N3
end

subgraph ANTLR["🌳 ANTLR Mode"]
direction TB
A1["ANTLR Lexer"]
A2["ANTLR Parser"]
A3["Full AST"]
A4["AST Walker"]
A1 --> A2 --> A3 --> A4
end

subgraph HYBRID["πŸ”€ Hybrid Mode (Default)"]
direction TB
H1["Query Arrives"]
H2["String Executor<br/>(Fast Path)"]
H3["Background Worker"]
H4["AST Cache"]

H1 --> H2
H1 -.-> |"async"| H3
H3 --> H4

style H2 fill:#238636,stroke:#3fb950
style H3 fill:#1f6feb,stroke:#58a6ff
style H4 fill:#6e40c9,stroke:#a371f7
end

NORNIC --> RESULT[("Result")]
ANTLR --> RESULT
HYBRID --> RESULT

HYBRID -.-> |"cached AST for<br/>LLM features"| LLM["πŸ€– LLM Integration"]

style ENV fill:#21262d,stroke:#30363d
style NORNIC fill:#161b22,stroke:#f85149
style ANTLR fill:#161b22,stroke:#a371f7
style HYBRID fill:#161b22,stroke:#3fb950
style RESULT fill:#238636,stroke:#3fb950
style LLM fill:#1f6feb,stroke:#58a6ff
```

## Query Flow Comparison

```mermaid
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1f6feb', 'primaryTextColor': '#c9d1d9', 'primaryBorderColor': '#30363d', 'lineColor': '#8b949e', 'secondaryColor': '#238636', 'tertiaryColor': '#21262d'}}}%%

sequenceDiagram
participant C as Client
participant N as Nornic
participant A as ANTLR
participant H as Hybrid
participant S as Storage
participant Cache as AST Cache

rect rgb(22, 27, 34)
Note over C,S: Nornic Mode (fastest)
C->>N: MATCH (n) RETURN n
N->>N: String parse (~0.1Β΅s)
N->>S: Execute
S-->>C: Results (~0.4Β΅s total)
end

rect rgb(22, 27, 34)
Note over C,S: ANTLR Mode (richest AST)
C->>A: MATCH (n) RETURN n
A->>A: Lexer + Parser (~15Β΅s)
A->>A: Build full AST
A->>A: Walk AST (~50Β΅s)
A->>S: Execute
S-->>C: Results (~70Β΅s total)
end

rect rgb(22, 27, 34)
Note over C,Cache: Hybrid Mode (best of both)
C->>H: MATCH (n) RETURN n
par Fast Path
H->>H: String parse
H->>S: Execute
S-->>C: Results (~0.4Β΅s)
and Background
H-->>Cache: Queue AST build
Cache->>Cache: ANTLR parse (async)
end
Note over Cache: AST ready for LLM features
end
```

## Mode Comparison

| Feature | ⚑ Nornic | 🌳 ANTLR | πŸ”€ Hybrid |
|---------|----------|----------|-----------|
| **Throughput** | 3,000-4,200 hz | 0.8-2,100 hz | 3,000-4,200 hz |
| **Benchmark Time** | 17.5s | 35.3s | 17.5s |
| **Worst Case Slowdown** | - | 4,753x | - |
| **Full AST Available** | ❌ No | βœ… Yes | βœ… Yes (async) |
| **LLM Query Manipulation** | ❌ Limited | βœ… Full support | βœ… Full support |
| **Memory Usage** | Lowest | Highest | Medium |
| **Query Validation** | Basic | Complete | Complete (async) |
| **Best For** | Max speed | Dev/Analysis | **Production + LLM** |

## Detailed Pros & Cons

### ⚑ Nornic Mode (`NORNICDB_EXECUTOR_MODE=nornic`)

**Pros:**
- πŸš€ **Fastest execution** - 420ns/op average
- πŸ’Ύ **Lowest memory** - No AST allocation
- πŸ”§ **Battle-tested** - Original implementation
- ⚑ **Zero parsing overhead** - Direct string manipulation

**Cons:**
- πŸ€– **No LLM integration** - Can't safely manipulate queries
- πŸ” **Limited introspection** - No structured query analysis
- πŸ› **Harder to debug** - No AST to inspect
- πŸ“Š **No query optimization** - Can't analyze query structure

**Use When:**
- Maximum performance is critical
- No LLM features needed
- Simple query patterns

---

### 🌳 ANTLR Mode (`NORNICDB_EXECUTOR_MODE=antlr`)

**Pros:**
- 🌳 **Full AST** - Complete parse tree for every query
- πŸ€– **LLM-ready** - Safe query manipulation/correction
- πŸ” **Rich introspection** - Analyze any query structure
- βœ… **Strict validation** - Grammar-enforced syntax checking
- πŸ› οΈ **Extensible** - Easy to add new Cypher features

**Cons:**
- 🐒 **Slowest execution** - ~165x slower than Nornic
- πŸ’Ύ **High memory** - Full parse tree allocation
- πŸ”„ **Parse overhead** - Every query fully parsed
- ⏱️ **Not for hot paths** - Too slow for high-throughput

**Use When:**
- Development and debugging
- Query analysis tools
- LLM features are the priority over speed
- Building query optimization pipelines

---

### πŸ”€ Hybrid Mode (`NORNICDB_EXECUTOR_MODE=hybrid`) **← DEFAULT**

**Pros:**
- ⚑ **Fast execution** - Same speed as Nornic (~3% overhead)
- 🌳 **AST available** - Built asynchronously in background
- πŸ€– **LLM-ready** - Cached AST for manipulation features
- 🎯 **Best of both** - Production speed + rich features
- πŸ“Š **Stats tracking** - Monitor cache hits/misses

**Cons:**
- πŸ’Ύ **Medium memory** - Caches grow over time
- πŸ”„ **Async complexity** - AST not immediately available
- ⏱️ **Cold start** - First query doesn't have cached AST
- 🧹 **Cache management** - May need periodic cleanup

**Use When:**
- **Production deployments** (recommended default)
- Need both speed and LLM features
- Can tolerate async AST availability
- Want monitoring/stats capabilities

---

## Performance Benchmarks

### Micro-benchmarks (M3 Max)

```
BenchmarkNornic_Execute-16 2,832,133 420.6 ns/op 128 B/op 4 allocs/op
BenchmarkHybrid_Execute-16 2,711,396 428.4 ns/op 128 B/op 4 allocs/op
BenchmarkANTLR_Execute-16 16,851 70,234.0 ns/op 45312 B/op 892 allocs/op
```

### Real-World Benchmarks (Northwind Database)

| Query | ⚑ Nornic (hz) | πŸ”€ Hybrid (hz) | 🌳 ANTLR (hz) | ANTLR Slowdown |
|-------|---------------|----------------|---------------|----------------|
| Count all nodes | 3,272 | 3,312 | 45 | **73x slower** |
| Count all relationships | 3,693 | 3,750 | 50 | **74x slower** |
| Find customer by ID | 4,213 | 4,009 | 2,153 | 2x slower |
| Products in Beverages category | 4,176 | 4,034 | 1,282 | 3x slower |
| Products supplied by Exotic Liquids | 4,023 | 4,133 | 53 | **76x slower** |
| Supplier→Category through products | 3,225 | 3,342 | 22 | **147x slower** |
| Products with/without orders | 3,881 | 3,967 | **0.82** | **4,753x slower** |
| Create and delete relationship | 3,974 | 3,956 | 62 | **64x slower** |

**Total benchmark time:**
- ⚑ Nornic: **17.5 seconds**
- πŸ”€ Hybrid: **17.5 seconds**
- 🌳 ANTLR: **35.3 seconds** (2x slower)

### Key Findings

1. **Hybrid = Nornic performance** - Zero measurable overhead in real workloads
2. **ANTLR is 50-5000x slower** depending on query complexity
3. **ANTLR catastrophic on complex queries** - Some queries take 1,224ms vs 0.25ms
4. **Hybrid is the clear winner** - Same speed as Nornic + AST for LLM features

## Configuration Examples

```bash
# Production (default) - fast + LLM ready
export NORNICDB_EXECUTOR_MODE=hybrid

# Maximum speed - no LLM features
export NORNICDB_EXECUTOR_MODE=nornic

# Development/Analysis - full AST always
export NORNICDB_EXECUTOR_MODE=antlr
```

## Startup Banner

When NornicDB starts, you'll see:

```
╔═══════════════════════════════════════════════════════════════════════╗
β•‘ πŸ”§ CYPHER EXECUTOR MODE: hybrid β•‘
β•‘ Hybrid executor - fast string execution + background AST building β•‘
β•‘ β•‘
β•‘ Set NORNICDB_EXECUTOR_MODE to: nornic | antlr | hybrid β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
```

## LLM Integration Architecture

```mermaid
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#1f6feb', 'primaryTextColor': '#c9d1d9', 'primaryBorderColor': '#30363d', 'lineColor': '#8b949e', 'secondaryColor': '#238636', 'tertiaryColor': '#21262d'}}}%%

flowchart LR
subgraph USER["User Input"]
Q1["Malformed Query"]
Q2["Natural Language"]
end

subgraph LLM["πŸ€– LLM Processing"]
direction TB
L1["Query Correction"]
L2["AST Analysis"]
L3["Safe Manipulation"]
end

subgraph HYBRID["πŸ”€ Hybrid Executor"]
direction TB
AST["Cached AST"]
EXEC["Fast Execution"]
end

Q1 --> L1
Q2 --> L1
L1 --> L2
AST --> L2
L2 --> L3
L3 --> EXEC
EXEC --> R[("Results")]

style USER fill:#21262d,stroke:#f85149
style LLM fill:#1f6feb,stroke:#58a6ff
style HYBRID fill:#238636,stroke:#3fb950
style R fill:#238636,stroke:#3fb950
```

## Related Files

- `pkg/config/executor_mode.go` - Configuration
- `pkg/cypher/executor_factory.go` - Factory function
- `pkg/cypher/hybrid_executor.go` - Hybrid implementation
- `pkg/cypher/ast_executor.go` - ANTLR implementation
- `pkg/cypher/executor.go` - Nornic (string) implementation

---

**Questions?** Open an issue or check the test files for usage examples:
- `pkg/cypher/executor_mode_test.go` - Comprehensive mode tests
- `pkg/cypher/hybrid_executor_test.go` - Hybrid-specific tests
2 changes: 2 additions & 0 deletions nornicdb/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
)

require (
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect
Expand All @@ -27,6 +28,7 @@ require (
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.34.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
Expand Down
4 changes: 4 additions & 0 deletions nornicdb/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
Expand Down Expand Up @@ -51,6 +53,8 @@ go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mx
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
Expand Down
Loading