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:

  1. 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.

  2. Learn relations: Aito discovers statistical relationships between fields (e.g., "description contains 'AWS'" correlates with "department = IT")

  3. Combine evidence: Multiple relations are combined using multiplicative lifts

  4. 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

OperationPurposeBest For
PredictEstimate a field value based on other fieldsClassification, auto-fill, routing
RecommendOptimize selections toward a goalProduct recommendations, next-best-action
MatchFind matching rows using all linked featuresCold-start matching, content-based filtering
SimilarityScore content similarityDuplicate 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:

  1. Computes base probability P(glCode) from historical frequency
  2. Finds relationships between description tokens and glCode values
  3. Combines evidence using multiplicative lifts
  4. 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:

  1. Filters employees where company = 42 (from the link constraint)
  2. Examines historical processor assignments for similar descriptions
  3. Weights candidates by their role and department patterns
  4. 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:

  1. Same inference mechanism as Predict
  2. But optimizes for goal achievement, not frequency
  3. A product that was shown rarely but purchased often ranks higher

Predict vs Recommend

AspectPredictRecommend
ObjectiveMimic historical patternsOptimize for goal
Use caseAuto-fill, classificationPersonalization, optimization
A product shown 100 times, purchased 5 timesHigher score (common)Lower score (5% conversion)
A product shown 10 times, purchased 5 timesLower 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:

  1. Uses inference based on statistical relations (like all operations)
  2. Considers ALL features of products (name, category, tags, description)
  3. Puts more emphasis on matched item properties than Predict does
  4. Data-efficient - can work well with relatively little training data

Match vs Predict

AspectMatchPredict
StatusDeprecatedPreferred
MathDifferent prior handlingClearer priors, more rigorous
Feature scopeEmphasizes matched item propertiesTreats linked properties as priors
HighlightingSupports $why feature highlightingNot yet supported
Use caseFree-text matching, record matchingPattern-based classification

Unique to Match:

  • Feature highlighting via $why shows 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:

  1. Tokenizes the query values
  2. Finds rows with matching tokens
  3. Weights matches using learned X-X priors (rarer terms typically get higher weights)
  4. 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:X may have a stronger prior than query: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:

  1. X-X relation: Query "banana" → products with "banana"
  2. 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:

  1. Examines co-occurrence patterns across features
  2. Identifies combinations that compress the data description (A & B & C patterns)
  3. 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" }
  ]
}
  • $p is 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:

MechanismDefaultWhat it doesFactor in $why
Support-temperingonTempers 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 calibrationopt-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.61 above) — 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

LeverExampleEffect 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.

StageProperty / EnvDefaultExampleEffect of changing
Representation learningaito.reexpInference.enabled / AITO_REEXP_INFERENCEtrueAITO_REEXP_INFERENCE=falseBaseline without learned feature combinations: faster per-state warmup, noticeably worse on correlated features (text especially). Per-query override: config.ai.
Hierarchical priorsaito.linkedTablePriors.enabled / AITO_LINKED_TABLE_PRIORStrueAITO_LINKED_TABLE_PRIORS=falseDisables linked-table priors — basedOn and cold-start quality degrade. Diagnosis only.
Support-temperingaito.neffTemper.enabled / AITO_NEFF_TEMPERtrueAITO_NEFF_TEMPER=falseRaw, un-tempered probabilities. Use for benchmark parity with older versions or external systems. Negligible speed impact either way.
— estimatoraito.neffTemper.mode / AITO_NEFF_TEMPER_MODEautoAITO_NEFF_TEMPER_MODE=coverageauto 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_KAPPA4.0AITO_NEFF_TEMPER_KAPPA=8Tempering strength for the fixed-κ modes (higher = softer probabilities). Ignored by auto.
Probability capaito.predictRowCap.enabled, aito.predictRowCap.k0true, 50-Daito.predictRowCap.k0=200Structural never-100% bound: $p ≤ 1 − 1/(k + k0) for k candidates. Larger k0 ⇒ looser cap (closer to uncapped); enabled=false removes it.
Redundancy discountaito.disc.enabled / AITO_DISCfalseAITO_DISC=trueExperimental. Extra down-weighting of correlated evidence beyond representation learning. Only relevant when representation learning is disabled.
Prior fitting schemeaito.priorSchememle-Daito.priorScheme=shrinkage:p0=0.5,W0=4.0,n0=1000Expert. Shrinks small-data adaptive-prior fits toward a neutral baseline; helps only on very small/noisy tables.

Recipes

  • Best quality (default) — change nothing: config.ai v2-equivalent learning, priors, support-tempering and the cap are all on.
  • Lowest latency"config": { "ai": "fast" } per query, plus tight candidate scoping in the where; 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=false and -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

Links resolve to depth 1 only:

  • processor.department works (one hop)
  • processor.company.industry does 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

Inference on linked fields requires:

  1. The link exists in the schema
  2. Types match exactly
  3. 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