| Crates.io | rust-rule-engine |
| lib.rs | rust-rule-engine |
| version | 1.18.1 |
| created_at | 2025-10-01 09:15:25.908576+00 |
| updated_at | 2026-01-23 02:06:36.164546+00 |
| description | A blazing-fast Rust rule engine with RETE algorithm, backward chaining inference, and GRL (Grule Rule Language) syntax. Features: forward/backward chaining, pattern matching, unification, O(1) rule indexing, TMS, expression evaluation, method calls, streaming with Redis state backend, watermarking, and custom functions. Production-ready for business rules, expert systems, real-time stream processing, and decision automation. |
| homepage | |
| repository | https://github.com/KSD-CO/rust-rule-engine |
| max_upload_size | |
| id | 1862298 |
| size | 4,210,967 |
A blazing-fast production-ready rule engine for Rust supporting both Forward and Backward Chaining. Features RETE-UL algorithm with Alpha Memory Indexing and Beta Memory Indexing, parallel execution, goal-driven reasoning, and GRL (Grule Rule Language) syntax.
๐ GitHub | Documentation | Crates.io
"When facts change, fire matching rules"
Use Cases: Business rules, validation, reactive systems, decision automation
"Given a goal, find facts/rules to prove it"
Use Cases: Expert systems, diagnostics, planning, decision support, AI reasoning
"Process real-time event streams with time-based windows"
Use Cases: Real-time fraud detection, IoT monitoring, financial analytics, security alerts, CEP
Example:
rule "Fraud Alert" {
when
login: LoginEvent from stream("logins") over window(10 min, sliding) &&
purchase: PurchaseEvent from stream("purchases") over window(10 min, sliding) &&
login.user_id == purchase.user_id &&
login.ip_address != purchase.ip_address
then
Alert.trigger("IP mismatch detected");
}
use rust_rule_engine::{RuleEngine, Facts, Value};
let mut engine = RuleEngine::new();
// Define rule in GRL
engine.add_rule_from_grl(r#"
rule "VIP Discount" {
when
Customer.TotalSpent > 10000
then
Customer.Discount = 0.15;
}
"#)?;
// Add facts and execute
let mut facts = Facts::new();
facts.set("Customer.TotalSpent", Value::Number(15000.0));
engine.execute(&mut facts)?;
// Result: Customer.Discount = 0.15 โ
use rust_rule_engine::backward::BackwardEngine;
let mut engine = BackwardEngine::new(kb);
// Query: "Can this order be auto-approved?"
let result = engine.query(
"Order.AutoApproved == true",
&mut facts
)?;
if result.provable {
println!("Order can be auto-approved!");
println!("Proof: {:?}", result.proof_trace);
}
use rust_rule_engine::parser::grl::stream_syntax::parse_stream_pattern;
use rust_rule_engine::rete::stream_alpha_node::{StreamAlphaNode, WindowSpec};
use rust_rule_engine::rete::working_memory::WorkingMemory;
// Parse GRL stream pattern
let grl = r#"login: LoginEvent from stream("logins") over window(5 min, sliding)"#;
let (_, pattern) = parse_stream_pattern(grl)?;
// Create stream processor
let mut node = StreamAlphaNode::new(
&pattern.source.stream_name,
pattern.event_type,
pattern.source.window.as_ref().map(|w| WindowSpec {
duration: w.duration,
window_type: w.window_type.clone(),
}),
);
// Process events in real-time
let mut wm = WorkingMemory::new();
for event in event_stream {
if node.process_event(&event) {
// Event passed filters and is in window
wm.insert_from_stream("logins".to_string(), event);
// Now available for rule evaluation!
}
}
// Run: cargo run --example streaming_fraud_detection --features streaming
Global cache for proven facts with dependency tracking and automatic invalidation for backward chaining!
1. Proof Caching
2. Dependency Tracking
3. TMS-Aware Invalidation
4. Search Integration
Seamlessly integrated into DepthFirstSearch and BreadthFirstSearch
Cache lookup before condition evaluation (early return on hit)
Automatic cache updates via inserter closure
use rust_rule_engine::backward::{BackwardEngine, DepthFirstSearch};
use rust_rule_engine::rete::IncrementalEngine;
// Create engines
let mut rete_engine = IncrementalEngine::new();
let kb = /* load rules */;
let mut backward_engine = BackwardEngine::new(kb);
// Create search with ProofGraph enabled
let search = DepthFirstSearch::new_with_engine(
backward_engine.kb().clone(),
Arc::new(Mutex::new(rete_engine)),
);
// First query builds cache
let result1 = backward_engine.query_with_search(
"eligible(?x)",
&mut facts,
Box::new(search.clone()),
)?;
// Subsequent queries use cache
let result2 = backward_engine.query_with_search(
"eligible(?x)",
&mut facts,
Box::new(search),
)?;
// Given rules: A โ B โ C (chain dependency)
let result_c = engine.query("C", &mut facts)?; // Proves A, B, C
// Retract A (premise)
facts.set("A", FactValue::Bool(false));
// Automatic cascading invalidation:
// A invalidated โ B invalidated โ C invalidated
// Total: 3 invalidations propagated through dependency graph
// Same fact proven 3 different ways:
// Rule 1: HighSpender โ eligible
// Rule 2: LoyalCustomer โ eligible
// Rule 3: Subscription โ eligible
let result = engine.query("eligible(?x)", &mut facts)?;
// ProofGraph stores all 3 justifications
// If one premise fails, others still valid!
Try it yourself:
# Run comprehensive demo with 5 scenarios
cargo run --example proof_graph_cache_demo --features backward-chaining
# Run integration tests
cargo test proof_graph --features backward-chaining
New Files:
src/backward/proof_graph.rs (520 lines) - Core ProofGraph implementationtests/proof_graph_integration_test.rs - 6 comprehensive testsexamples/09-backward-chaining/proof_graph_cache_demo.rs - Interactive demoFeatures:
Removed 5 external dependencies - replaced with Rust stdlib or removed dead code:
Replaced with stdlib:
num_cpus โ โ
std::thread::available_parallelism() (Rust 1.59+)once_cell โ โ
std::sync::OnceLock (Rust 1.70+)fastrand โ โ
std::collections::hash_map::RandomStateRemoved unused:
petgraph - Declared but never used (zero code references)futures - Declared but never used (tokio is sufficient)Benefits:
Final Core Dependencies: Only 7 essential crates
chrono, log, nom, regex, serde, serde_json, thiserror
Optional dependencies (by feature):
tokio - Async runtime for streamingredis - State backend for streaming-redisCode changes:
num_cpus::get() โ std::thread::available_parallelism()once_cell::Lazy โ std::sync::OnceLockfastrand โ RandomState::new().build_hasher()Testing:
Complete implementation of session-based windowing for real-time event streams! Session windows dynamically group events based on inactivity gaps rather than fixed time boundaries.
What are Session Windows?
Unlike sliding or tumbling windows, session windows adapt to natural event patterns:
Events: A(t=0), B(t=1), C(t=2), [gap 10s], D(t=12), E(t=13)
Timeout: 5 seconds
Result:
Session 1: [A, B, C] - ends when gap > 5s
Session 2: [D, E] - starts after gap > 5s
GRL Syntax:
rule "UserSessionAnalysis" {
when
activity: UserAction from stream("user-activity")
over window(5 min, session)
then
AnalyzeSession(activity);
}
Rust API:
use rust_rule_engine::rete::stream_alpha_node::{StreamAlphaNode, WindowSpec};
use rust_rule_engine::streaming::window::WindowType;
use std::time::Duration;
let window = WindowSpec {
duration: Duration::from_secs(60),
window_type: WindowType::Session {
timeout: Duration::from_secs(5), // Gap threshold
},
};
let mut node = StreamAlphaNode::new("user-events", None, Some(window));
Perfect for:
Features:
cargo run --example session_window_demo --features streamingMajor cleanup and optimization of the project structure for better maintainability and developer experience!
๐ง Dependencies Optimized (-75% dev-deps)
Benefits:
+=)Added support for the += operator to append values to arrays in GRL actions! This is particularly useful for building recommendation lists, accumulating results, and managing collections.
GRL Syntax:
rule "Product Recommendation" salience 100 no-loop {
when
ShoppingCart.items contains "Laptop" &&
!(Recommendation.items contains "Mouse")
then
Recommendation.items += "Mouse"; // Append to array
Recommendation.items += "USB-C Hub"; // Multiple appends
Log("Added recommendations");
}
Rust Usage:
use rust_rule_engine::rete::{IncrementalEngine, TypedFacts, FactValue};
use rust_rule_engine::rete::grl_loader::GrlReteLoader;
let mut engine = IncrementalEngine::new();
GrlReteLoader::load_from_file("rules.grl", &mut engine)?;
let mut facts = TypedFacts::new();
facts.set("ShoppingCart.items", FactValue::Array(vec![
FactValue::String("Laptop".to_string())
]));
facts.set("Recommendation.items", FactValue::Array(vec![]));
engine.insert_typed_facts("ShoppingCart", facts.clone());
engine.fire_all(&mut facts, 10);
// Result: Recommendation.items = ["Mouse", "USB-C Hub"] โ
Integration with Rule Mining:
The += operator works seamlessly with rust-rule-miner for automatic rule generation:
// Mine association rules from historical data
let rules = miner.mine_association_rules()?;
// Export to GRL with += syntax
let grl = GrlExporter::to_grl(&rules);
// Generates: Recommendation.items += "Phone Case";
// Load and execute in RETE engine
GrlReteLoader::load_from_string(&grl, &mut engine)?;
Supported Everywhere:
Comprehensive documentation organized by topic:
๐ Full Documentation Index โ
See CHANGELOG.md for full version history (v0.1.0 - v0.19.0).