# Slot Resolution System
A modular, scalable system for resolving entity names to IDs using Elasticsearch fuzzy matching with disambiguation support.
## π― Overview
The Slot Resolution System automatically converts natural language entity references (e.g., "high impact", "shivam") to their corresponding database IDs. It supports multiple modules (request, problem, change) with configurable field mappings and contextual filters.
### Key Features
- **Multi-Stage Resolution**: Normalization β Exact Match β Alias Match β Fuzzy ES Match β Decisioning
- **Disambiguation Support**: Handles multiple matches with user elicitation
- **Configurable Thresholds**: Per-entity min scores and score gap deltas
- **Contextual Filtering**: Apply filters like `userType=technician` during resolution
- **Caching**: Request-level memoization and LRU caching for performance
- **Audit Logging**: Complete audit trail for compliance
- **Modular Architecture**: Clean separation of concerns with SOLID principles
## π Project Structure
```
slot_resolution/
βββ __init__.py # Package exports
βββ README.md # This file
β
βββ config/ # Configuration Layer
β βββ __init__.py
β βββ field_mappings.json # Field-to-entity mappings
β βββ config_loader.py # Configuration loader
β
βββ core/ # Core Layer
β βββ __init__.py
β βββ models.py # Data models
β βββ normalizer.py # Input normalization
β βββ resolver.py # Core resolution engine
β βββ decisioning.py # Score-based decisioning
β
βββ services/ # Services Layer
β βββ __init__.py
β βββ exact_match_service.py # Exact matching
β βββ alias_service.py # Alias/synonym matching
β βββ elasticsearch_service.py # ES fuzzy matching
β βββ cache_service.py # Caching layer
β βββ audit_service.py # Audit logging
β
βββ middleware/ # Middleware Layer
β βββ __init__.py
β βββ slot_resolution_middleware.py # Request transformation
β
βββ utils/ # Utilities
βββ __init__.py
βββ exceptions.py # Custom exceptions
```
## π Quick Start
### Installation
The slot resolution system is part of your project. Ensure dependencies are installed:
```bash
pip install elasticsearch>=8.0.0
```
### Basic Usage
```python
from elasticsearch_search_lib import SearchClient
from slot_resolution import SlotResolutionMiddleware
from slot_resolution.core.resolver import SlotResolver
from slot_resolution.services.elasticsearch_service import ElasticsearchMatchingService
# 1. Create Elasticsearch search client
search_client = SearchClient(tenant_id="apolo")
# 2. Create Elasticsearch matching service
es_service = ElasticsearchMatchingService(search_client)
# 3. Create slot resolver
resolver = SlotResolver(es_service=es_service)
# 4. Create middleware
middleware = SlotResolutionMiddleware(
tenant_id="apolo",
resolver=resolver
)
# 5. Resolve a request
request_payload = {
"subject": "Laptop not working",
"impact": "high",
"assignee": "shivam"
}
result = await middleware.resolve_request(
request_payload=request_payload,
module="request"
)
if result.status == "READY":
print("Transformed payload:", result.payload)
# Output: {"subject": "Laptop not working", "impactId": 2, "technicianId": 433}
elif result.status == "DISAMBIGUATION_REQUIRED":
print("Disambiguation needed:", result.disambiguations)
```
## π Configuration
### Field Mappings
Field mappings are defined in `config/field_mappings.json`:
```json
{
"request": [
{
"columnName": "impact",
"primitiveType": "long",
"referenceTo": "impact",
"dbKey": "impactId",
"required": true
},
{
"columnName": "assignee",
"primitiveType": "long",
"referenceTo": "user",
"dbKey": "technicianId",
"required": false,
"filters": {
"userType": "technician",
"active": true
}
}
]
}
```
**Fields:**
- `columnName`: Field name in incoming request (e.g., "impact", "assignee")
- `primitiveType`: Data type (e.g., "long", "string")
- `referenceTo`: Entity type to search in Elasticsearch (e.g., "impact", "user")
- `dbKey`: Target field name in transformed request (e.g., "impactId", "technicianId")
- `required`: Whether field is required
- `filters`: Optional contextual filters to apply during resolution
### Adding New Modules
To add support for a new module (e.g., "asset"):
1. Add configuration to `field_mappings.json`:
```json
{
"asset": [
{
"columnName": "assetType",
"primitiveType": "long",
"referenceTo": "assettype",
"dbKey": "assetTypeId",
"required": true
}
]
}
```
2. Use the middleware with the new module:
```python
result = await middleware.resolve_request(
request_payload=asset_payload,
module="asset"
)
```
## π Resolution Flow
```
User Request
β
βββββββββββββββββββββββββββββββββββββββ
β 1. Normalization β
β "High" β "high" β
βββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 2. Cache Lookup β
β Check if already resolved β
βββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 3. Exact Match β
β Case-insensitive name match β
βββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 4. Alias Match β
β "hi" β "high" β
βββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 5. Elasticsearch Fuzzy Match β
β Multi-field bool query β
β with fuzziness=AUTO β
βββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 6. Decisioning β
β - Single match β RESOLVED β
β - Multiple matches β DISAMBIGUATEβ
β - No matches β NO_MATCH β
βββββββββββββββββββββββββββββββββββββββ
```
## π Response Formats
### Successful Resolution
```json
{
"status": "READY",
"payload": {
"subject": "Laptop not working",
"impactId": 2,
"technicianId": 433
},
"auditTrail": {
"impact": {
"status": "RESOLVED",
"original_value": "high",
"resolved_id": "2",
"resolved_name": "High",
"confidence": 0.97
}
}
}
```
### Disambiguation Required
```json
{
"status": "DISAMBIGUATION_REQUIRED",
"disambiguations": [
{
"field": "assignee",
"targetField": "technicianId",
"candidates": [
{
"id": "433",
"canonicalName": "Shivam Pansuriya",
"entityType": "user",
"confidence": 0.78,
"attributes": {
"emailDomain": "motadata.com",
"department": "Engineering"
}
},
{
"id": "434",
"canonicalName": "Shivam Kumar",
"entityType": "user",
"confidence": 0.75,
"attributes": {
"emailDomain": "motadata.com",
"department": "Support"
}
}
],
"originalInput": "shivam"
}
]
}
```
## ποΈ Advanced Configuration
### Custom Decision Thresholds
```python
from slot_resolution.core.decisioning import DecisionEngine
# Create custom decision engine
decision_engine = DecisionEngine(
min_scores={
"impact": 0.70,
"user": 0.75
},
score_gap_delta=0.20,
max_candidates=3
)
# Use in resolver
resolver = SlotResolver(
es_service=es_service,
decision_engine=decision_engine
)
```
### Enable Caching
```python
from slot_resolution.services.cache_service import CacheService
# Create cache service
cache_service = CacheService(
ttl_seconds=900, # 15 minutes
max_size=1000
)
# Use in resolver
resolver = SlotResolver(
es_service=es_service,
cache_service=cache_service
)
```
### Enable Audit Logging
```python
from slot_resolution.services.audit_service import AuditService
# Create audit service
audit_service = AuditService(
log_to_file=True,
log_file_path="slot_resolution_audit.log"
)
# Use in resolver
resolver = SlotResolver(
es_service=es_service,
audit_service=audit_service
)
```
## π§ͺ Testing
```python
import asyncio
from slot_resolution import SlotResolutionMiddleware
async def test_resolution():
# Setup
middleware = SlotResolutionMiddleware(tenant_id="apolo", resolver=resolver)
# Test case 1: Successful resolution
result = await middleware.resolve_request(
request_payload={"impact": "high"},
module="request"
)
assert result.status == "READY"
assert "impactId" in result.payload
# Test case 2: Disambiguation
result = await middleware.resolve_request(
request_payload={"assignee": "john"},
module="request"
)
if result.status == "DISAMBIGUATION_REQUIRED":
print(f"Found {len(result.disambiguations[0].candidates)} candidates")
asyncio.run(test_resolution())
```
## π Performance
- **Target Latency**: p95 < 300ms
- **Cache Hit Rate**: β₯ 70%
- **Resolution Rate**: β₯ 95%
- **Top-1 Accuracy**: β₯ 95%
## π Security
- **Tenant Isolation**: All queries scoped to tenant ID
- **PII Protection**: Sensitive fields redacted in logs
- **Input Validation**: All inputs sanitized and validated
## π License
Internal use only - Motadata ITSM Team