Rule Engine Application with Abstract Syntax Tree (AST) - README
This application is a Flask-based rule engine that evaluates user eligibility based on complex, customizable rules. It uses an Abstract Syntax Tree (AST) for structured rule representation and supports dynamic rule creation, combination, and evaluation.
Application Architecture
Layers:
-
UI Layer:
- Manages rule visualization and user interactions for creating, modifying, and viewing rules.
-
API Layer:
- Provides endpoints for creating, combining, and evaluating rules dynamically.
-
Database Layer:
- Stores rules in a structured format, including both the rule strings and AST representations in JSON.
Endpoints and Functions:
/get_rules: Fetches all rules from the database./create_rule: Parses the rule string into an AST and stores it in the database./combine_rules: Combines multiple rules into a single AST, supporting complex eligibility criteria./evaluate_rule: Evaluates the eligibility of a user based on input data against a specified AST.
AST Representation:
- Each rule’s AST is represented using
Nodeobjects. These nodes include:- Operators: Logical operations like
ANDandOR. - Operands: Conditions such as
age > 30ordepartment = 'Sales'.
- Operators: Logical operations like
- AST operations handle complex nested conditions and prevent redundancy in rule evaluation.
Example:
A rule such as (age > 30 AND department = 'Sales') would be represented as:
{
"type": "operator",
"value": "AND",
"left": {
"type": "operand",
"value": "age > 30"
},
"right": {
"type": "operand",
"value": "department = 'Sales'"
}
}Error Handling and Validation:
- The system includes checks for malformed rules, invalid attribute values, and database operation failures.
- Response codes:
- 400: Bad requests, e.g., malformed rules.
- 500: Server errors.
Improvements and Considerations:
-
Testing:
- Unit tests should be added for each function, particularly for parsing and evaluating rules.
-
Data Validation:
- Improved validation in
evaluate_ruleto ensure that data types (e.g., integer forage) match rule conditions.
- Improved validation in
-
Performance:
- To improve performance under high load, consider caching frequently used rules or optimizing the rule engine.
Future Extensions:
-
User-Defined Functions (UDFs):
- Allowing user-defined functions within rules could offer greater flexibility, enabling custom evaluation logic.
-
Rule Versioning:
- Adding versioning for rules would allow rollback capabilities and better tracking of rule changes.
Example API Usage
Endpoint: /create_rule
Request:
{
"rule_string": "(age > 30 AND department = 'Sales')"
}Response:
{
"ast": {
"type": "operator",
"value": "AND",
"left": {
"type": "operand",
"value": "age > 30"
},
"right": {
"type": "operand",
"value": "department = 'Sales'"
}
}
}Endpoint: /combine_rules
Request:
{
"rules": [
"((age > 30 AND department = 'Sales') OR (age < 25 AND department = 'Marketing')) AND (salary > 50000 OR experience > 5)",
"((age > 30 AND department = 'Marketing')) AND (salary > 20000 OR experience > 5)"
]
}Response:
{
"combined_ast": {
"type": "operator",
"value": "AND",
"left": {
// Nested JSON structure for the combined AST
}
}
}Endpoint: /evaluate_rule
Request:
{
"ast": {
"type": "operator",
"value": "OR",
"left": {
"type": "operator",
"value": "AND",
"left": {
"type": "operand",
"value": "age > 30"
},
"right": {
"type": "operand",
"value": "department = 'Sales'"
}
},
"right": {
"type": "operand",
"value": "income < 50000"
}
},
"data": {
"age": 35,
"department": "Sales",
"income": 45000
}
}Response:
{
"is_eligible": true
}Endpoint: /get_rules
Response:
{
"rules": [
{
"id": 1,
"rule_string": "(age > 30 AND department = 'Sales')",
"ast_json": "{...AST representation in JSON...}"
},
{
"id": 2,
"rule_string": "(age > 30 AND department = 'Sales')",
"ast_json": "{...AST representation in JSON...}"
}
]
}Setup
-
Clone the Repository:
git clone <repository-url> cd rule-engine-ast
-
Install Dependencies:
pip install -r requirements.txt
-
Run the Application:
python app.py