Inference Guide
This guide explains how Aito's inference operations work: predict, recommend, match, and similarity. Understanding these mechanisms helps you design effective schemas and write better queries.
See it in action: Explore the demo workbook to run live predict and recommend queries yourself.
How Inference Works
Aito learns relationships from your data and combines them to make predictions. The pipeline:
-
Representation learning: Aito automatically discovers higher-level patterns from raw features using MDL (Minimum Description Length) principles. Co-occurring features are combined into meaningful concepts without manual feature engineering.
-
Learn relations: Aito discovers statistical relationships between fields (e.g., "description contains 'AWS'" correlates with "department = IT")
-
Combine evidence: Multiple relations are combined using multiplicative lifts
-
Use priors: Aito always combines observations with hierarchical priors (priors dominate when data is sparse)
This happens automatically - you provide data, Aito learns the patterns and representations.
Operations Overview
| Operation | Purpose | Best For |
|---|---|---|
| Predict | Estimate a field value based on other fields | Classification, auto-fill, routing |
| Recommend | Optimize selections toward a goal | Product recommendations, next-best-action |
| Match | Find matching rows using all linked features | Cold-start matching, content-based filtering |
| Similarity | Score content similarity | Duplicate detection, similar item search |
Predict
Predict estimates the most likely value for a field based on patterns learned from your data.
Basic Predict
{
"from": "invoices",
"where": {
"description": "Office supplies and stationery"
},
"predict": "glCode"
}
How it works:
- Computes base probability
P(glCode)from historical frequency - Finds relationships between description tokens and glCode values
- Combines evidence using multiplicative lifts
- Returns probability distribution over possible values
Linked Column Prediction
When the prediction target is a linked field, Aito leverages attributes from the linked table:
{
"from": "invoices",
"where": {
"description": "IT equipment maintenance contract",
"processor.company": 42
},
"predict": "processor",
"basedOn": ["role", "department"]
}
What happens:
- Filters employees where
company = 42(from the link constraint) - Examines historical processor assignments for similar descriptions
- Weights candidates by their
roleanddepartmentpatterns - Returns probability distribution over employee IDs
The basedOn Parameter
basedOn specifies which attributes of the linked entity to consider:
"basedOn": ["role", "department"]
Key constraints:
- Operates on the linked table (employees, not invoices)
- Depth 1 only - cannot traverse multi-hop links (A→B→C)
- Reduces noise by focusing on relevant attributes
- If omitted, uses all attributes of the linked entity
Example - with and without basedOn:
// Without basedOn: uses all employee attributes (name, email, etc.)
{
"from": "invoices",
"where": { "description": "Server maintenance" },
"predict": "processor"
}
// With basedOn: focuses on role and department patterns
{
"from": "invoices",
"where": { "description": "Server maintenance" },
"predict": "processor",
"basedOn": ["role", "department"]
}
Recommend
Recommend is like Predict, but optimizes toward a goal instead of mimicking historical behavior.
Basic Recommend
{
"from": "impressions",
"where": {
"context.query": "laptop",
"context.user": "user123"
},
"recommend": "product",
"goal": { "purchase": true }
}
How it works:
- Same inference mechanism as Predict
- But optimizes for goal achievement, not frequency
- A product that was shown rarely but purchased often ranks higher
Predict vs Recommend
| Aspect | Predict | Recommend |
|---|---|---|
| Objective | Mimic historical patterns | Optimize for goal |
| Use case | Auto-fill, classification | Personalization, optimization |
| A product shown 100 times, purchased 5 times | Higher score (common) | Lower score (5% conversion) |
| A product shown 10 times, purchased 5 times | Lower score (rare) | Higher score (50% conversion) |
Match
Note: Match is deprecated in favor of Predict. They work conceptually in a similar manner, but Predict uses clearer priors and more mathematically rigorous inference. Match may still perform better in specific use cases (e.g., job-to-person matching, record matching to master data).
Match finds rows using all features behind the link, leveraging learned relations across all attributes of the linked entity.
Basic Match
{
"from": "messages",
"where": {
"content": "Need a premium laptop for software development"
},
"match": "product"
}
How it works:
- Uses inference based on statistical relations (like all operations)
- Considers ALL features of products (name, category, tags, description)
- Puts more emphasis on matched item properties than Predict does
- Data-efficient - can work well with relatively little training data
Match vs Predict
| Aspect | Match | Predict |
|---|---|---|
| Status | Deprecated | Preferred |
| Math | Different prior handling | Clearer priors, more rigorous |
| Feature scope | Emphasizes matched item properties | Treats linked properties as priors |
| Highlighting | Supports $why feature highlighting | Not yet supported |
| Use case | Free-text matching, record matching | Pattern-based classification |
Unique to Match:
- Feature highlighting via
$whyshows which attributes contributed to the match - May perform better for specific matching tasks (job matching, master data matching)
When to use Predict (recommended):
- General classification and routing
- When you want clearer probability semantics
- Higher data volume with clear historical signal
- When only some attributes matter (use
basedOn)
Similarity
Similarity scores rows based on shared content, primarily using X-X relations.
Basic Similarity
{
"from": "products",
"similarity": {
"name": "premium laptop",
"category": "electronics"
}
}
How it works:
- Tokenizes the query values
- Finds rows with matching tokens
- Weights matches using learned X-X priors (rarer terms typically get higher weights)
- Returns rows sorted by combined similarity score
Similarity emphasizes X-X content matching over other learned patterns, making it ideal for finding duplicates or similar items based on shared content.
Hierarchical Priors
Aito always combines direct observations with hierarchical priors - learned patterns from similar relations. With lots of data, observed statistics dominate the result; with little or no data, priors play a bigger role. This is fundamental to how all inference operations work.
How Priors Work
Aito builds a hierarchy of priors from general to specific:
General: "search term X" → "product contains X" (X-X pattern)
↓
Specific: "search term 'banana'" → "product contains 'banana'"
The specific relation uses the general pattern as a prior, then adjusts based on observed data.
X-X Relations (Same-Value Matching)
When the same value appears in different fields, Aito learns whether this is generally positive or negative. X-X priors are field-specific - each field pair has its own learned prior strength:
Positive X-X (search terms → products):
- Query "banana" → products with "banana" in name
- Prior is positive because search terms generally match desired products
Negative X-X (previous purchases → next purchase):
- Previous purchase "ketchup" → next purchase "ketchup"
- Prior is negative because people rarely buy the same item twice in a row
Field-specific prior strength:
query:X → title:Xmay have a stronger prior thanquery:X → description:X- This is learned from the history of X-to-X relationships for each field pair
- Different field pairs develop different prior strengths based on observed patterns
The X-X prior is not a fixed formula - it's learned from aggregated statistics. If "apple-apple", "orange-orange", "banana-banana" relations are generally positive for a field pair, new terms get a positive prior for that pair.
Property-Based Priors
Priors also flow through linked properties:
Specific: "description:AWS" → "assignee:employee_42"
↓ uses as prior
General: "description:AWS" → "assignee.department:IT"
And for name matching:
Specific: "description:Bob" → "assignee:employee_1"
↓ uses as prior
Property: "description:Bob" → "assignee.name:Bob"
↓ uses as prior
Pattern: "description:X" → "assignee.name:X" (X-X relation)
This hierarchy lets Aito make reasonable predictions even for combinations it hasn't seen, by leveraging patterns from similar relations.
X-X-Y Pattern in Recommend
Recommend especially leverages X-X relations combined with outcomes:
X (keyword) ←→ X (product attribute) → Y (outcome)
Example:
{
"from": "impressions",
"where": { "context.query": "banana" },
"recommend": "product",
"goal": { "purchase": true }
}
Aito combines:
- X-X relation: Query "banana" → products with "banana"
- X-Y relation: Products with "banana" → purchase likelihood
This is why recommend works well with new search terms - even without historical "banana query → purchase" data, the X-X matching provides signal.
Representation Learning
Aito automatically learns higher-level representations from raw features, eliminating the need for manual feature engineering.
How It Works
Aito uses MDL (Minimum Description Length) principles to discover meaningful feature combinations:
- Examines co-occurrence patterns across features
- Identifies combinations that compress the data description (A & B & C patterns)
- Creates higher-level representations from these combinations
Example:
If entities frequently have walks_like_duck, swims_like_duck, and quacks_like_duck together, Aito recognizes this as a unified concept rather than treating them as independent features.
Applied Consistently
Representation learning is applied to both:
- Context features (the input query/where clause)
- Predicted property variables used in priors (e.g., attributes of linked entities)
This consistency makes priors better behaved - the same learned representations are used when computing both direct evidence and prior estimates.
Why This Matters
No manual feature engineering: You don't need to create features like is_weekend or high_value_customer - Aito discovers these patterns automatically.
Better disambiguation: The system distinguishes between similar but distinct concepts. For example, "machine learning" and "machine maintenance" are recognized as different concepts despite sharing the word "machine".
Transparent explanations: When you use $why, the discovered patterns appear as logical feature combinations, making results interpretable.
Probability Scores
All inference operations return probability scores between 0 and 1.
Understanding Scores
{
"hits": [
{ "$p": 0.85, "field": "glCode", "$value": "5100" },
{ "$p": 0.12, "field": "glCode", "$value": "5200" },
{ "$p": 0.03, "field": "glCode", "$value": "5300" }
]
}
$pis the probability score- Scores sum to 1.0 across all candidates (for exclusive predictions)
- Higher scores indicate stronger evidence
Score Calibration
Aito's scores are calibrated probabilities, meaning:
- A score of 0.85 means ~85% accuracy when that score is returned
- Useful for setting confidence thresholds
- If score < 0.5, consider flagging for human review
Two mechanisms keep the probabilities calibrated. Both are visible as explicit
calibration factors in $why, so the factor breakdown always multiplies out to the
displayed $p:
| Mechanism | Default | What it does | Factor in $why |
|---|---|---|---|
| Support-tempering | on | Tempers each prediction's confidence by the effective statistical support of its evidence. Well-supported predictions pass through unchanged; thin or heavily overlapping evidence is softened towards the prior. Deterministic lookups and $knn/$nn matches count as well-supported and are not softened. | support-tempering(auto) |
| Query-time calibration | opt-in: "config": { "calibrate": true } | Fits a global temperature τ per (table, target) on top of support-tempering, correcting residual mis-calibration. | temperature(τ=…) |
Example. A predict with "select": ["$p", "id", "$why"]:
{
"from": "invoices",
"where": {
"description": "Monthly cloud infrastructure invoice",
"processor.company": 758
},
"predict": "processor",
"basedOn": ["role", "department"],
"select": ["$p", "id", "$why"]
}
The top hit's $why then carries the calibration factors alongside the normalizers
(response excerpt, factor list of the winning candidate):
{
"$p": 0.3147,
"id": 33771,
"$why": {
"type": "product",
"factors": [
{ "type": "baseP", "value": 2.41e-4 },
{ "type": "normalizer", "name": "exclusiveness", "value": 0.52 },
{ "type": "normalizer", "name": "trueFalseExclusiveness", "value": 0.02 },
{ "type": "calibration", "name": "support-tempering(auto)", "value": 0.61 },
{ "type": "relatedPropositionLift", "...": "..." }
]
}
}
How to read the support-tempering(auto) value:
- ≈ 1.0 — the evidence is well supported; the probability is essentially raw.
- well below 1.0 (like
0.61above) — the prediction rests on thin or overlapping evidence and its confidence was softened. More (or broader) training data will raise both the confidence and its trustworthiness. - The factor multiplies into the displayed
$p— no hidden post-processing.
Tuning Inference
This section is the reference for tuning the quality / calibration / speed trade-off. Work top-down: the per-query levers cover almost every real need without touching the deployment; the deployment flags exist for A/B comparison, diagnosis, and opt-outs.
Per-query levers
| Lever | Example | Effect on quality / speed |
|---|---|---|
| Inference preset | "config": { "ai": "fast" } | Selects the representation-learning preset. v2 / high (And + Group learning): best quality on correlated features. v1 / and, group: individual learners for A/B. fast / flat: no representation learning — lowest latency, weaker where features correlate. Unknown names fail loud. |
| Query-time calibration | "config": { "calibrate": true } | Fits and applies a temperature τ per (table, target); fitted once per DB state, then cached — first query pays the fit. Use when held-out log-loss matters. |
| Candidate scoping | "where": { "processor.company": 42 } | Constrain the target's attributes to shrink the candidate set — improves both precision and latency (fewer candidates to score). |
| Prior shaping | "basedOn": ["role", "department"] | Which linked-table fields build the cold-start prior. The main quality lever when history is sparse. |
| Fuzzy numerics | "company.size": { "$numeric": 500 } | Match numbers by neighbourhood instead of exactly — smooths sparse numeric evidence. |
| Nested context | "$context": { … } | Reference fields of the from table inside nested/linked propositions. |
| Inspection | "select": ["$p", "$why"] | See the full factor breakdown (evidence, priors, calibration) per hit. Slightly larger responses; use while tuning, drop in production hot paths. |
Measure every change with _evaluate (accuracy, meanRank,
informationGain) — see Improving inference for the workflow.
Deployment flags
JVM system properties (env-variable forms where given). Defaults are the validated production configuration; change them for A/B baselines or special cases, not routine tuning.
| Stage | Property / Env | Default | Example | Effect of changing |
|---|---|---|---|---|
| Representation learning | aito.reexpInference.enabled / AITO_REEXP_INFERENCE | true | AITO_REEXP_INFERENCE=false | Baseline without learned feature combinations: faster per-state warmup, noticeably worse on correlated features (text especially). Per-query override: config.ai. |
| Hierarchical priors | aito.linkedTablePriors.enabled / AITO_LINKED_TABLE_PRIORS | true | AITO_LINKED_TABLE_PRIORS=false | Disables linked-table priors — basedOn and cold-start quality degrade. Diagnosis only. |
| Support-tempering | aito.neffTemper.enabled / AITO_NEFF_TEMPER | true | AITO_NEFF_TEMPER=false | Raw, un-tempered probabilities. Use for benchmark parity with older versions or external systems. Negligible speed impact either way. |
| — estimator | aito.neffTemper.mode / AITO_NEFF_TEMPER_MODE | auto | AITO_NEFF_TEMPER_MODE=coverage | auto is self-scaling (no parameters) and recommended. count / harmonic / coverage are fixed-κ estimators for research; count is known to over-temper sparse text. |
| — κ | aito.neffTemper.kappa / AITO_NEFF_TEMPER_KAPPA | 4.0 | AITO_NEFF_TEMPER_KAPPA=8 | Tempering strength for the fixed-κ modes (higher = softer probabilities). Ignored by auto. |
| Probability cap | aito.predictRowCap.enabled, aito.predictRowCap.k0 | true, 50 | -Daito.predictRowCap.k0=200 | Structural never-100% bound: $p ≤ 1 − 1/(k + k0) for k candidates. Larger k0 ⇒ looser cap (closer to uncapped); enabled=false removes it. |
| Redundancy discount | aito.disc.enabled / AITO_DISC | false | AITO_DISC=true | Experimental. Extra down-weighting of correlated evidence beyond representation learning. Only relevant when representation learning is disabled. |
| Prior fitting scheme | aito.priorScheme | mle | -Daito.priorScheme=shrinkage:p0=0.5,W0=4.0,n0=1000 | Expert. Shrinks small-data adaptive-prior fits toward a neutral baseline; helps only on very small/noisy tables. |
Recipes
- Best quality (default) — change nothing:
config.aiv2-equivalent learning, priors, support-tempering and the cap are all on. - Lowest latency —
"config": { "ai": "fast" }per query, plus tight candidate scoping in thewhere; representation learning is the main per-query cost. - Best calibration — keep defaults and add
"config": { "calibrate": true }on the predicts whose probabilities feed thresholds or downstream decisions. - Raw-probability baseline (benchmarks, migration comparison) —
AITO_NEFF_TEMPER=falseand-Daito.predictRowCap.enabled=false, ideally in a separate environment; re-enable for production.
For where to set deployment flags in a cluster, see the operations manual's configuration reference.
Inference Limits
Relation Selection
Aito selects up to 32 relations per variable for inference:
- Relations are prioritized by information gain (mutual information)
- High-dimensional data may have relevant relations excluded
- This is rarely a practical limitation
Link Depth
Links resolve to depth 1 only:
processor.departmentworks (one hop)processor.company.industrydoes not work (two hops)- Resolve deeper chains in your application logic
Query Examples
Auto-fill Invoice Fields
{
"from": "invoices",
"where": {
"description": "Monthly cloud hosting fees - AWS",
"company": 42
},
"predict": "glCode"
}
Product Recommendations
{
"from": "impressions",
"where": {
"user": "user_456",
"context.basket": ["laptop", "mouse"]
},
"recommend": "product",
"goal": { "purchase": true }
}
Find Similar Products
{
"from": "products",
"similarity": {
"name": "wireless bluetooth headphones",
"tags": ["audio", "wireless"]
},
"limit": 10
}
Match Message to Product (Cold Start)
{
"from": "conversations",
"where": {
"message": "Looking for a quiet keyboard for office work"
},
"match": "product"
}
Scoped Employee Prediction
{
"from": "invoices",
"where": {
"description": "Legal consulting services",
"processor.company": 42,
"processor.department": "Legal"
},
"predict": "processor",
"basedOn": ["role"]
}
Debugging Tips
Check Your Schema Links
Inference on linked fields requires:
- The link exists in the schema
- Types match exactly
- Target table has data
Verify Training Data
For Predict/Recommend:
- Need examples where the prediction target has values
- More examples = better accuracy
- Diverse examples improve generalization
Examine Score Distribution
If all scores are similar (e.g., all around 0.1):
- May indicate insufficient training data
- Or the where clause doesn't provide distinguishing information
- Try adding more context to the where clause
Related
- Schema Design - How to design schemas for inference
- Query Comparison - Choosing the right query type
- Predict Endpoint - API reference