Introduction

Welcome to Aito HTTP API reference documentation. You can also test out the queries in the interactive Swagger UI.

Start here: Explore the demo workbook to see Aito in action before diving into the API. The workbook shows live predictions, recommendations, and queries you can run yourself.

Examples are shown in this column.

Live Demo

The examples in this documentation use data from the Aito Grocery Store Demo - a fully functional e-commerce application showcasing 13 production-ready ML features including personalized recommendations, smart search, automated tagging, and invoice processing.

You can explore the demo at demo.aito.ai or test the API directly using the public endpoint at https://shared.aito.ai/db/aito-demo/api/v1/ (no signup required).

The demo dataset includes 134 users, 42 products, and over 90,000 interaction records, demonstrating real-world ML scenarios with sub-100ms query latency.

Use case guides:

Operational guides:

  • Environments - Branch the database into named copies for sandboxes, per-user demos, and atomic releases

Getting Started

What is Aito?

Aito is a predictive database that combines the query capabilities of a traditional database with built-in machine learning. Instead of building and training separate ML models, you simply query Aito with questions like "predict the most likely tag for this product" or "recommend products for this user" - and get instant, accurate results.

Try it now

No signup required! The demo database is publicly accessible. Try this query to predict which product category a user is most likely to purchase:

curl -X POST \
  'https://shared.aito.ai/db/aito-demo/api/v1/_predict' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "impressions",
    "where": {
      "context.user": "veronica"
    },
    "predict": "product.category"
  }'

Understanding the response

Aito returns predictions ranked by probability. Each hit includes:

  • $p - the probability of this outcome
  • feature - the predicted value
  • field - which field was predicted

Core operations

You want to...UseReturns
Filter and retrieve dataSearchDeterministic matches
Predict a category or valuePredictProbabilistic classification
Rank items by goal likelihoodRecommendSorted by relevance
Estimate a numeric valueEstimateK-NN regression
Find similar itemsSimilarityDistance-ranked matches
Discover data correlationsRelateStatistical relationships
Measure ML accuracyEvaluateAccuracy metrics

For a detailed comparison with runnable examples, see the Query Comparison Guide.

Next steps

Guides

Example response:

{
  "offset": 0,
  "total": 5,
  "hits": [
    {
      "$p": 0.42,
      "field": "product.category",
      "feature": "Drinks"
    },
    {
      "$p": 0.28,
      "field": "product.category",
      "feature": "Snacks"
    },
    {
      "$p": 0.15,
      "field": "product.category",
      "feature": "Dairy"
    }
  ]
}

Authentication

All requests must specify an API key in the x-api-key header. There are two types of authentication keys:

  • read-only Allows only read queries. Good for sharing access to 3rd parties.
  • read/write Allows all queries.

Client configuration

We recommend setting up your Aito instance configuration using environment variables as follows:

Environment variableValue
AITO_INSTANCE_URLyour-aito-instance-url
AITO_API_KEYyour-api-key

These environment variables are recognized by the Aito Python SDK. The URL and API keys can be found on the instance overview page in the Aito Console.

Limitations

Your instance might have monthly and burst API call limits. Refer to the pricing page for details.

Payload size is limited to 10MB per message. This includes data and all headers. For uploading larger datasets to the database, the file upload API can be used to overcome this limit.

Queries must be completed within 30 seconds, or they will time out. In this case, the API Gateway will return an HTTP 504 Gateway Timeout error. This is a hard limit set by AWS and cannot be modified.

API access limits cannot be enforced on an IP or hostname basis. The authentication is based on an API key. The API is served only over secure HTTP.

Pagination

Some endpoints use pagination to limit the amount of results returned at once. The pagination is based on offset and limit parameters, similar to SQL and many other APIs.

As an example, to get the first result set of 10 items with Search query you can request:

{
  "from": "products",
  "offset": 0,
  "limit": 10
}

The response will have a total field, which tells you how many items were found in total:

{
  "offset": 0,
  "total": 81,
  "hits": [ ... ]
}

If this exceeds the amount of items in hits array, it means some results were filtered out from the response. To request the next 10 items, you can query:

{
  "from": "products",
  "offset": 10,
  "limit": 10
}

The default values for pagination parameters are the following.

ParameterDefault value
offset0
limit10

Formatting

Responses are served by default as compact json. If you want to have server-side pretty-printed responses, as was the earlier default, you can add the header x-aito-prettyprint: true to your API-request.

CORS

All responses are served with access-control-allow-origin: * headers. This is useful for browser applications.

Aito-specific concepts

We aim for a familiar API, but in some cases Aito has different default behavior than other databases.

Descending order by default

By default, Aito sorts everything from the largest to the smallest. This is a design choice dictated by the fact that in statistical reasoning, the highest values are often the most interesting ones.

For example: the items with the highest probabilities, the highest frequencies, the highest similarities, the highest mutual information, and the highest scores are often the most desired ones.

Use $asc to sort values from the smallest to the biggest, as shown in the example:

{
  "from": "products",
  "where": {
    "category.id": 89
  },
  "orderBy": {
    "$asc": "price"
  }
}

Personalisation

Aito has been designed to work well even with small data sets. One example of this is how personalized recommendations work. This is easiest to understand with an example—let's use the Aito grocery demo.

When requesting product recommendations for a customer who's a vegetarian, Aito also considers what non-vegetarians purchase. For example, if the customer were the only vegetarian user of the grocery web shop, they could receive meat recommendations if other users purchased a lot of meat.

This behavior is usually desirable. In book, music, movie, and many other recommendation scenarios, you commonly want to discover new items instead of getting recommendations only from your own history. However, in some cases this behavior might lead to unexpected predictions. For example if we predicted how likely a vegetarian is to purchase bacon, Aito could return that it is very likely, because based on data, that's the common average.

An example recommend query could look like this:

{
  "from": "impressions",
  "where": { "context.user": "veronica" },
  "recommend": "product",
  "goal": { "purchase": true }
}

Even if we limit the data to impressions by veronica, Aito still considers other data points.

Error handling

In error cases, we return with proper HTTP status codes. Error responses:

  • 400 Bad Request Returned when there's an error with the given request payload. For example invalid query syntax.
  • 429 Too Many Requests Returned when a query limit is hit. The response contains a header called x-error-cause which indicates the cause of the error and it is either Quota Exceeded or Throttled. The query quota is reset each month. You can increase it by upgrading the tier of your instance, see the terms of service for details. A request is throttled when there are too many requests per second. A throttled request should be retried after a short delay and will likely succeed as soon as the overall request rate drops.

Example error

Error returned when trying to use incorrect table name. Instead of prodjucts, it should be products.

{
  "charOffset": 17,
  "lineNumber": 3,
  "columnNumber": 13,
  "error": "failed to open 'prodjucts'",
  "status": 400,
  "message": "3:13: failed to open 'prodjucts'\n\n      \"from\": \"prodjucts\"\n              ^\n",
  "messageLines": [
    "3:13: failed to open 'prodjucts'",
    "",
    "      \"from\": \"prodjucts\"",
    "              ^"
  ]
}

Valid table names

Aito Database names cannot have whitespaces (spaces, tabs, linefeeds etc.) or any of the following characters:

/\".$

These name validation rules were progressively applied in June. If you have invalid tables, you can use schema/_rename end point to rename them.

Common query errors

For a comprehensive guide on troubleshooting query errors, see the Common Query Errors page. It covers:

  • Unknown field/table errors
  • Type mismatches
  • Empty result sets
  • JSON syntax issues
  • Rate limits and timeouts

Feedback & bug reports

We take our quality seriously and aim for the smoothest developer experience possible. If you run into problems, please send an email to support@aito.ai containing reproduction steps and we'll fix it as soon as possible.

Query API

The query language operations.

Search

POST/api/v1/_search

Search rows.

Allows you to search, filter, and order rows. You can also select only specific columns. Similar to SELECT in SQL.

I The results are in descending order by default.

Aito supports intuitive link following. If your products table has a link column called category that links to a categories table, you can simply use dot notation in your query:

{
  "from": "products",
  "where": {
    "category.id": 89
  },
  "orderBy": "price"
}

Get all rows

You can easily select all rows from a table with the following query:

{
  "from": "products"
}

Note: the amount of results is limited to 10 by default.

Highlighted results

If you want to get search results with highlights, see Generic query.

See in action

Find by id

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "where": {
    "id": "6411300000494"
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_search \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": { "id": "6411300000494" }
  }'

Response

{
  "offset": 0,
  "total": 1,
  "hits": [
    {
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    }
  ]
}

Where price is greater than

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "where": {
    "price": {
      "$gt": 1.5
    }
  },
  "limit": 2
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_search \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "price": { "$gt": 1.5 }
    },
    "limit": 2
  }'

Response

{
  "offset": 0,
  "total": 21,
  "hits": [
    {
      "category": "101",
      "cost": 1.183,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "6437002001454",
      "name": "VAASAN Ruispalat 660g 12 pcs fullcorn rye bread",
      "price": 1.69,
      "tags": [
        "gluten",
        "bread"
      ]
    },
    {
      "category": "101",
      "cost": 1.295,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "6411402202208",
      "name": "Fazer Puikula fullcorn rye bread 9 pcs/500g",
      "price": 1.85,
      "tags": [
        "gluten",
        "bread"
      ]
    }
  ]
}

Find products with search term

Request body

{
  "from": "products",
  "where": {
    "name": {
      "$match": "coffee"
    }
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_search \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "name": { "$match": "coffee" }
    }
  }'

Response

{
  "offset": 0,
  "total": 4,
  "hits": [
    {
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    },
    {
      "category": "108",
      "cost": 2.415,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6420101441542",
      "name": "Kulta Katriina filter coffee 500g",
      "price": 3.45,
      "tags": [
        "coffee"
      ]
    },
    {
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300164653",
      "name": "Juhla Mokka Dark Roast coffee 500g hj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    },
    {
      "category": "108",
      "cost": 2.023,
      "googleClicks": 7,
      "googleImpressions": 100,
      "id": "6410405181190",
      "name": "Pirkka Costa Rica filter coffee 500g UTZ",
      "price": 2.89,
      "tags": [
        "coffee",
        "pirkka"
      ]
    }
  ]
}

More complex where proposition

Find all products priced over 1.5€, which have tag drink or their name matches to coffee.

Request body

{
  "from": "products",
  "where": {
    "$and": [
      {
        "$or": [
          {
            "tags": {
              "$has": "drink"
            }
          },
          {
            "name": {
              "$match": "coffee"
            }
          }
        ]
      },
      {
        "price": {
          "$gt": 1.5
        }
      }
    ]
  },
  "limit": 2
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_search \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "$and": [
        {
          "$or": [
            {
              "tags": { "$has": "drink" }
            },
            {
              "name": { "$match": "coffee" }
            }
          ]
        },
        {
          "price": { "$gt": 1.5 }
        }
      ]
    },
    "limit": 2
  }'

Response

{
  "offset": 0,
  "total": 6,
  "hits": [
    {
      "category": "104",
      "cost": 1.365,
      "googleClicks": 8,
      "googleImpressions": 100,
      "id": "6408430000258",
      "name": "Valio eila™ Lactose-free semi-skimmed milk drink 1l",
      "price": 1.95,
      "tags": [
        "lactose-free",
        "drink"
      ]
    },
    {
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    }
  ]
}

Predict

POST/api/v1/_predict

Predict the likelihood of a feature given a hypothesis.

For example, predict what other products a user could add to their e-commerce shopping cart, based on the existing cart. To understand why Aito predicts certain results, you can select "$why".

Narrowing prediction targets

You can narrow down the prediction targets by using the where clause. For example, when predicting a processor for an invoice, you can select only employees from a specific department to be considered as candidates.

{
  "from": "invoices",
  "where": {
    "Name": "Aws Cloud",
    "Processor.Department": "IT & Infrastructure"
  },
  "predict": "Processor"
}

Priors with linked content

If prediction is done on a variable that links to another table, Aito will use the table content to form a "prior estimate"—a kind of initial guess.

The prior estimate allows inferring information about prediction targets without historical data. For example, if we are predicting an invoice processor, it is possible to adjust predictions for new employees based on their properties like role or department.

Priors can also use information about word matching. For example, if an invoice contains the word "CTO", this can raise the prior probability for employees with that role. Similarly, if an invoice contains the name "Jane", this may raise the prior probability for employees named Jane. This word matching is based on average statistics—for instance, if invoices with descriptions containing X have historically had processors containing X in their role or name fields.

You can select the fields used in prior estimation via the basedOn field. The default is to use all fields in the linked table. It is advisable to limit the number of fields used, as unrelated fields may add noise to results. Prior estimation also has some performance cost, which can be mitigated by reducing the number of fields or disabling priors entirely.

Note: If there is a lot of historical data, the inference results will be dominated by direct historical evidence, and the prior effects will be muted.

Related information

  • The exclusiveness option is explained in Exclusiveness chapter.
  • The chapter Personalisation also explains a characteristic of predictions in Aito.

See in action

Guides

Predict invoice processor

In this example, we predict who should process an invoice based on the invoice name. Aito learns from historical invoice assignments to predict the most suitable processor.

The invoices table contains invoice records with fields like Name, ProductName, Description, and Processor (who handled the invoice).

Request body

{
  "from": "invoices",
  "where": {
    "ProductName": "Cloud Services (AWS)"
  },
  "predict": "Processor"
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "invoices",
    "where": { "ProductName": "Cloud Services (AWS)" },
    "predict": "Processor"
  }'

Response

{
  "offset": 0,
  "total": 10,
  "hits": [
    {
      "$p": 0.9337657201523418,
      "Department": "IT & Infrastructure",
      "Name": "Carol White",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.0516357326584329,
      "Department": "IT & Infrastructure",
      "Name": "Evelyn Carter",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Executive",
      "Name": "John Doe",
      "Role": "CEO"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Finance",
      "Name": "Jane Smith",
      "Role": "CFO",
      "Superior": "John Doe"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Operations",
      "Name": "Alice Johnson",
      "Role": "COO",
      "Superior": "John Doe"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "IT & Infrastructure",
      "Name": "Bob Brown",
      "Role": "CTO",
      "Superior": "John Doe"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Retail",
      "Name": "David Green",
      "Role": "Store Manager",
      "Superior": "Alice Johnson"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Finance",
      "Name": "Emily Davis",
      "Role": "Finance Manager",
      "Superior": "Jane Smith"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Operations",
      "Name": "Frank Wilson",
      "Role": "Operations Manager",
      "Superior": "Alice Johnson"
    },
    {
      "$p": 0.001824818398653149,
      "Department": "Support",
      "Name": "Bob Smith",
      "Role": "Support Manager",
      "Superior": "Frank Wilson"
    }
  ]
}

Explain the prediction

Same example as above, but we ask Aito to explain why it predicted the results. To understand the response, see "$why" section.

Request body

{
  "from": "invoices",
  "where": {
    "ProductName": "Cloud Services (AWS)"
  },
  "select": [
    "$why"
  ],
  "predict": "Processor"
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "invoices",
    "where": { "ProductName": "Cloud Services (AWS)" },
    "select": ["$why"],
    "predict": "Processor"
  }'

Response

{
  "offset": 0,
  "total": 10,
  "hits": [
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.27927927927927926,
            "proposition": {
              "Processor": {
                "$has": "Carol White"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9063112955641688
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.7819694103328909
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 3.008095352553848
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 1.0898263027295285
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 1.090760543073411
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.018018018018018018,
            "proposition": {
              "Processor": {
                "$has": "Evelyn Carter"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9125084670548561
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.09970784411904586
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.002117082416732
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 10.971631810738481
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 1.494044665012407
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 1.4991829869037605
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "John Doe"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "Jane Smith"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "Alice Johnson"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "Bob Brown"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.4594594594594595,
            "proposition": {
              "Processor": {
                "$has": "David Green"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 10.655524709586313
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 6580.421813504648
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 0.9759251433171361
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.05336871096408597
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.1891891891891892,
            "proposition": {
              "Processor": {
                "$has": "Emily Davis"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 2.2385284844622313
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 25624.07148049561
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0050444509317449
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.15384615384615383
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "Frank Wilson"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    },
    {
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.047619047619047616,
            "proposition": {
              "Processor": {
                "$has": "Bob Smith"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.2789959853871087
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.232766079977389
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 656765.947241007
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "servic"
              }
            },
            "value": 1.0315364281557005
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "$group": [
                {
                  "ProductName": {
                    "$has": "aw"
                  }
                },
                {
                  "ProductName": {
                    "$has": "cloud"
                  }
                }
              ]
            },
            "value": 0.042191252080053594
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "cloud"
              }
            },
            "value": 0.01191066997518605
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "ProductName": {
                "$has": "aw"
              }
            },
            "value": 0.00007138965562650521
          }
        ]
      }
    }
  ]
}

Example request

In the example we're predicting three suitable tags for a hypothetical new product based on its name. Tags are predicted based on what tags existing products have.

Request body

{
  "from": "products",
  "where": {
    "name": "Hovis Seed Sensations Seven Seeds Original 800g"
  },
  "predict": "tags",
  "exclusiveness": false,
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": { "name": "Hovis Seed Sensations Seven Seeds Original 800g" },
    "predict": "tags",
    "exclusiveness": false,
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 25,
  "hits": [
    {
      "$p": 0.2593630824234764,
      "field": "tags",
      "feature": "pirkka"
    },
    {
      "$p": 0.22468683081458513,
      "field": "tags",
      "feature": "food"
    },
    {
      "$p": 0.19001057920569392,
      "field": "tags",
      "feature": "meat"
    }
  ]
}

Example request

In this example, we predict the invoice processor based on the invoice description and product name.

Because the processor variable links to the employees table, the results will contain employee table details.

This prediction will also use by default the employee table details like 'role', 'department' and 'superior' to provide prior or initial guess to the prediction.

Because the prior, the second hit in the results is the new IT manager Evelyn Carter, even when she has never processed an invoice before in the demo data.

Request body

{
  "from": "invoices",
  "where": {
    "ProductName": "Cloud Services (AWS)",
    "Description": "For IT Department"
  },
  "predict": "Processor",
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "invoices",
    "where": {
      "ProductName": "Cloud Services (AWS)",
      "Description": "For IT Department"
    },
    "predict": "Processor",
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 10,
  "hits": [
    {
      "$p": 0.9545989374572562,
      "Department": "IT & Infrastructure",
      "Name": "Carol White",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.03080249444154766,
      "Department": "IT & Infrastructure",
      "Name": "Evelyn Carter",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.0018248210126495105,
      "Department": "Executive",
      "Name": "John Doe",
      "Role": "CEO"
    }
  ]
}

Example request

This is similar example as above, except that we also limit the prediction to only those employees that are in the IT & Infrastructure department.

Also the prediction prior is solely based on the employee 'Role'. This will make the prediction ignore fields like 'Department', as it's known to be IT & Infrastructure, the name, which can introduce noise to results, and the superior, which is doesn't bring additional information, if department and role are known.

Because the prior, the new IT manager is predicted to be a more likely invoice processor than the CTO.

Request body

{
  "from": "invoices",
  "where": {
    "ProductName": "Cloud Services (AWS)",
    "Description": "For IT Department",
    "Processor.Department": "IT & Infrastructure"
  },
  "predict": "Processor",
  "basedOn": [
    "Role"
  ],
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "invoices",
    "where": {
      "ProductName": "Cloud Services (AWS)",
      "Description": "For IT Department",
      "Processor.Department": "IT & Infrastructure"
    },
    "predict": "Processor",
    "basedOn": ["Role"],
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 3,
  "hits": [
    {
      "$p": 0.9576430281873831,
      "Department": "IT & Infrastructure",
      "Name": "Carol White",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.03301114401373869,
      "Department": "IT & Infrastructure",
      "Name": "Evelyn Carter",
      "Role": "IT Manager",
      "Superior": "Bob Brown"
    },
    {
      "$p": 0.009345827798878228,
      "Department": "IT & Infrastructure",
      "Name": "Bob Brown",
      "Role": "CTO",
      "Superior": "John Doe"
    }
  ]
}

Recommend

POST/api/v1/_recommend

Recommend a row which optimizes a given goal.

For example, you could ask Aito to choose a product, which maximizes the click likelihood, when user id equals 4543.

Recommend differs from predict and match in the following way: recommend always optimizes a goal, while predict and match merely mimic existing behavior patterns in the data. As an example, consider the problem of matching employees to projects. With predict and match, you can mimic the way projects are staffed currently, and Aito will replicate both good and bad staffing practices. With recommend, Aito seeks to maximize the success rate and avoid decisions that lead to bad outcomes, even if these decisions were a popular practice.

The chapter Personalisation also explains a characteristic of the recommendations.

See in action

Guides

Recommend top 5 products for a customer

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In the example we're recommending the top 5 products which veronica (user id) would most likely to purchase based on her behavior history stored in impressions table. The table contains information of which products she has seen and which of those where bought.

This query could be used to generate campaign email which recommends relevant products for a customer.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "veronica"
  },
  "recommend": "product",
  "goal": {
    "purchase": true
  },
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_recommend \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "veronica" },
    "recommend": "product",
    "goal": { "purchase": true },
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.19266411598455546,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6410405093677",
      "name": "Pirkka iceberg salad Finland 100g 1st class",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "salad"
      ]
    },
    {
      "$p": 0.16679522498673674,
      "category": "100",
      "cost": 0.586,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "2000604700007",
      "name": "Cucumber Finland",
      "price": 0.9765,
      "tags": [
        "fresh",
        "vegetable"
      ]
    },
    {
      "$p": 0.161778166328556,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$p": 0.13527444193705185,
      "category": "100",
      "cost": 0.168,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "2000503600002",
      "name": "Chiquita banana",
      "price": 0.28054,
      "tags": [
        "fresh",
        "fruit"
      ]
    },
    {
      "$p": 0.11674813114595652,
      "category": "111",
      "cost": 1.61,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6414880021620",
      "name": "Ilta Sanomat weekend news",
      "price": 2.3,
      "tags": [
        "news"
      ]
    }
  ]
}

Recommend top products with additional filtering

This example is the same as above, but we're adding an additional criteria: the product name should match to 'Banana' search query.

This query could be used to build a personalised search functionality.

Request body

{
  "from": "impressions",
  "where": {
    "product.name": {
      "$match": "Banana"
    },
    "context.user": "veronica"
  },
  "recommend": "product",
  "goal": {
    "purchase": true
  },
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_recommend \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": {
      "product.name": { "$match": "Banana" },
      "context.user": "veronica"
    },
    "recommend": "product",
    "goal": { "purchase": true },
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 2,
  "hits": [
    {
      "$p": 0.161778166328556,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$p": 0.13527444193705185,
      "category": "100",
      "cost": 0.168,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "2000503600002",
      "name": "Chiquita banana",
      "price": 0.28054,
      "tags": [
        "fresh",
        "fruit"
      ]
    }
  ]
}

Estimate

POST/api/v1/_estimate

Estimate numeric field values using K-NN with transformation pipelines.

! The Estimate operation is in beta stage. The API syntax and behavior may change based on user feedback.

The Estimate query predicts numeric values (like price, quantity, or revenue) by finding similar instances in your data and using their values to make an intelligent prediction. It combines K-Nearest Neighbors (K-NN) with optional transformation pipelines to handle complex numeric relationships.

How it works

  1. Find similar instances: Aito finds the K most similar instances based on your where clause
  2. Learn patterns: Automatically learns categorical effects and linear relationships from the data
  3. Transform values: Removes learned effects to normalize the data
  4. Estimate: Computes the average of the K nearest neighbors
  5. Restore: Applies the learned effects back to get the final prediction

Estimation Algorithms

The query supports two estimation algorithms (specified via the model field):

  • knn (default): Adjusted knn is best for datasets with local linear patterns. Uses transformation pipelines to normalize values before K-NN averaging, then restores the context-specific effects.
  • regression: Best for globally linear relationships. Uses pure linear regression without K-NN averaging.

Explanation Support

You can request detailed explanations by including "$why" in the select field. The explanation will show:

  • Which neighbors were used in the estimation
  • What categorical and linear effects were learned
  • How the transformation pipeline affected the prediction
  • The contribution of each feature to the final estimate

See the "$why" section for more details on score explanations.

Use Cases

  • Price estimation: Predict product prices based on category, brand, and features
  • Demand forecasting: Estimate sales quantities based on historical patterns
  • Revenue prediction: Predict invoice amounts based on product type and customer
  • Resource planning: Estimate time or cost based on project characteristics

Comparison with Predict

While _predict is designed for categorical outcomes (predicting which category), _estimate is designed for numeric outcomes (predicting how much). Use _predict for classification tasks and _estimate for regression tasks.

Related information

  • See Evaluate for measuring estimation accuracy
  • The chapter on K-NN explains the neighbor selection process

See in action

Estimate product price

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In this example, we estimate the sale price of a product from the price history based on the sales context.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "bread"
    }
  },
  "estimate": "price",
  "select": [
    "estimate"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_estimate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "bread" }
    },
    "estimate": "price",
    "select": ["estimate"]
  }'

Response

{
  "estimate": 1.350545069703815
}

Estimate product price

Same example as above, but we use simpler regression model instead of the default neighbors model with regression adjustment.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "bread"
    }
  },
  "estimate": "price",
  "model": "regression",
  "select": [
    "estimate"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_estimate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "bread" }
    },
    "estimate": "price",
    "model": "regression",
    "select": ["estimate"]
  }'

Response

{
  "estimate": 1.350545069703815
}

Estimate with explanation

Same example as above, but we ask Aito to explain how it estimated the result. The explanation shows which neighbors were used, what categorical effects were learned, and how they contributed to the final estimate.

To understand the response, see "why" section.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "bread"
    }
  },
  "estimate": "price",
  "model": "regression",
  "select": [
    "estimate",
    "why"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_estimate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "bread" }
    },
    "estimate": "price",
    "model": "regression",
    "select": ["estimate", "why"]
  }'

Response

{
  "estimate": 1.350545069703815,
  "why": {
    "type": "exponent",
    "value": 1.3505450697038148,
    "base": {
      "type": "constant",
      "value": 2.718281828459045
    },
    "power": {
      "type": "sum",
      "terms": [
        {
          "type": "input",
          "name": "residual",
          "value": 0
        },
        {
          "type": "mean centering",
          "name": "mean",
          "value": 0.30050826629924476
        }
      ]
    }
  }
}

Estimate with explanation

This time we are looking at price history table to estimate the number of units sold. Sale_price is used as a parameter.

Request body

{
  "from": "price_history",
  "where": {
    "product_id": "2000818700008",
    "day_of_week": "Friday",
    "competitor_avg_price": 0.18,
    "sale_price": 0.16
  },
  "estimate": "units_sold",
  "select": [
    "estimate"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_estimate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "price_history",
    "where": {
      "product_id": "2000818700008",
      "day_of_week": "Friday",
      "competitor_avg_price": 0.18,
      "sale_price": 0.16
    },
    "estimate": "units_sold",
    "select": ["estimate"]
  }'

Response

{
  "estimate": 242.74868764966547
}

Evaluate

POST/api/v1/_evaluate

Evaluate performance and accuracy.

The query supports evaluation of Predict, Match, Similarity, Estimate, and Generic queries.

For a step-by-step walkthrough — metrics, choosing the test set, and running long evaluations — see the Evaluation guide.

The evaluation is performed by first specifying the train and test data split:

  • The training data: The data that will be used to train Aito.
  • The testing data: The data that will be hidden from Aito and will be used to measure an Aito query's performance.

The testing data is specified using the test proposition or the TestSource. The training data is the remaining data that is not the testing data.

The evaluating query is specified following the evaluate keyword.

After that, a simulated evaluation scenario is run: Aito simulates inserting the training data into a table and then runs the given query for each sample (row) in the test data and measures how good the results were.

It is also possible to group multiple entries into a single test case using the EvaluateGroupedQuery.

Controlling the test set

Evaluate runs one query per test row, so the cost grows with the size of the test set. Keep runs fast and bounded by selecting test rows explicitly. The simplest way is the $sample proposition, which picks a fixed number of rows and is deterministic by default (the same rows every run, unless you pass a seed):

"test": { "$sample": 100 }
"test": { "$sample": { "n": 100, "of": { "app": "X" }, "seed": 0 } }

The TestSource gives more control when you need it — where to filter or sample which rows are tested, limit/offset to take a window, and from to draw the test set from a different table:

"testSource": { "where": { "$sample": 100 }, "select": ["query"] }
"testSource": { "from": "testData", "limit": 100 }

For a deterministic fraction of the data, $hash + $mod splits pseudo-randomly, e.g. { "id": { "$hash": { "$mod": [10, 0] } } }.

I If you provide neither test nor testSource, evaluate defaults to a random sample of 100 rows ({ "$sample": 100 }) rather than testing against the whole collection, and notes this in the response message.

Time limit and cancellation

Each evaluate query has a time budget set with maxTime (seconds, default 300, capped at 3600). If the budget is exhausted, evaluate returns partial results for the rows completed so far, with truncated: true, the number of requested rows, and an explanatory message. Raise maxTime, narrow the test set, or run the query as a cancellable job for longer evaluations.

For long-running evaluations, submit the query as an asynchronous job and poll for the result:

  • POST /api/v1/jobs/_evaluate — start the evaluation as a job
  • GET /api/v1/jobs/{id} — check job status
  • GET /api/v1/jobs/{id}/result — fetch the result once finished
  • DELETE /api/v1/jobs/{id}cancel a running job

See in action

Example request

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In the example we're evaluating how good results Aito provides when we predict category for a new hypothetical product. The results give us the accuracy and performance of the prediction example shown in Predict operation's documentation.

$index is a built-in variable which tells the insertion index of a row. In the example, we select 1/4 of the rows in products table to be used as test data. The rest of the rows are automatically used as training data.

Aito iterates through each product in the test data, and tests how accurate the prediction of category for a given product name was.

Request body

{
  "test": {
    "$index": {
      "$mod": [
        4,
        0
      ]
    }
  },
  "evaluate": {
    "from": "products",
    "where": {
      "name": {
        "$match": {
          "$get": "name"
        }
      }
    },
    "predict": "category"
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_evaluate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "test": {
      "$index": {
        "$mod": [4, 0]
      }
    },
    "evaluate": {
      "from": "products",
      "where": {
        "name": {
          "$match": { "$get": "name" }
        }
      },
      "predict": "category"
    }
  }'

Response

{
  "n": 11,
  "testSamples": 11,
  "trainSamples": 31,
  "features": 235,
  "error": 0.4545454545454546,
  "baseError": 0.9090909090909091,
  "accuracy": 0.5454545454545454,
  "baseAccuracy": 0.09090909090909091,
  "accuracyGain": 0.4545454545454545,
  "meanRank": 2.090909090909091,
  "baseMeanRank": 4.090909090909091,
  "rankGain": 2,
  "informationGain": 1.8582343968781507,
  "mxe": 1.8275510300793094,
  "h": 3.350714024506782,
  "geomMeanP": 0.28174247236980876,
  "baseGmp": 0.09802448555185775,
  "geomMeanLift": 2.874205059926165,
  "meanNs": 24878721.545454547,
  "meanUs": 24878.721545454548,
  "meanMs": 24.878721545454546,
  "medianNs": 23412571,
  "medianUs": 23412.571,
  "medianMs": 23.412571,
  "allNs": [
    27293651,
    19898483,
    32846835,
    29484480,
    17991653,
    31010331,
    43609281,
    23412571,
    21858708,
    12954390,
    13305554
  ],
  "allUs": [
    27293,
    19898,
    32846,
    29484,
    17991,
    31010,
    43609,
    23412,
    21858,
    12954,
    13305
  ],
  "allMs": [
    27,
    19,
    32,
    29,
    17,
    31,
    43,
    23,
    21,
    12,
    13
  ],
  "warmingMs": 7,
  "accurateOffsets": [
    2,
    4,
    5,
    6,
    7,
    8
  ],
  "errorOffsets": [
    0,
    1,
    3,
    9,
    10
  ],
  "cases": [
    {
      "offset": 0,
      "testCase": {
        "category": "100",
        "cost": 0.1,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "2000818700008",
        "name": "Pirkka banana",
        "price": 0.166,
        "tags": [
          "fresh",
          "fruit",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1295991145436842,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.11857669800109355,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 1,
      "testCase": {
        "category": "100",
        "cost": 0.774,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6410405093677",
        "name": "Pirkka iceberg salad Finland 100g 1st class",
        "price": 1.29,
        "tags": [
          "fresh",
          "vegetable",
          "pirkka",
          "salad"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1295991145436842,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.11857669800109355,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 2,
      "testCase": {
        "category": "101",
        "cost": 0.903,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6413467282508",
        "name": "Fazer Puikula fullcorn rye bread 330g",
        "price": 1.29,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9836065573770494,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.9836065573770494,
        "field": "category",
        "feature": "101"
      }
    },
    {
      "offset": 3,
      "testCase": {
        "category": "102",
        "cost": 1.953,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410405205483",
        "name": "Pirkka Finnish beef-pork minced meat 20% 400g",
        "price": 2.79,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1439259526572726,
        "field": "category",
        "feature": "103"
      },
      "correct": {
        "$p": 0.08785487117032287,
        "field": "category",
        "feature": "102"
      }
    },
    {
      "offset": 4,
      "testCase": {
        "category": "103",
        "cost": 1.393,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6412000030026",
        "name": "Saarioinen Maksalaatikko liver casserole 400g",
        "price": 1.99,
        "tags": [
          "meat",
          "food"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.141419991195898,
        "field": "category",
        "feature": "103"
      },
      "correct": {
        "$p": 0.141419991195898,
        "field": "category",
        "feature": "103"
      }
    },
    {
      "offset": 5,
      "testCase": {
        "category": "104",
        "cost": 0.567,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "6410405082657",
        "name": "Pirkka Finnish semi-skimmed milk 1l",
        "price": 0.81,
        "tags": [
          "lactose",
          "drink",
          "pirkka"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9721508335126348,
        "field": "category",
        "feature": "104"
      },
      "correct": {
        "$p": 0.9721508335126348,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 6,
      "testCase": {
        "category": "104",
        "cost": 1.365,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6408430000258",
        "name": "Valio eila™ Lactose-free semi-skimmed milk drink 1l",
        "price": 1.95,
        "tags": [
          "lactose-free",
          "drink"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.6242204303115763,
        "field": "category",
        "feature": "104"
      },
      "correct": {
        "$p": 0.6242204303115763,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 7,
      "testCase": {
        "category": "108",
        "cost": 2.415,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6420101441542",
        "name": "Kulta Katriina filter coffee 500g",
        "price": 3.45,
        "tags": [
          "coffee"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9762803781616086,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.9762803781616086,
        "field": "category",
        "feature": "108"
      }
    },
    {
      "offset": 8,
      "testCase": {
        "category": "109",
        "cost": 1.533,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6411401015090",
        "name": "Fazer Sininen milk chocolate slab 200g",
        "price": 2.19,
        "tags": [
          "candy",
          "lactose"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.33912840860958743,
        "field": "category",
        "feature": "109"
      },
      "correct": {
        "$p": 0.33912840860958743,
        "field": "category",
        "feature": "109"
      }
    },
    {
      "offset": 9,
      "testCase": {
        "category": "111",
        "cost": 2.345,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6413200330206",
        "name": "Lotus Soft Embo 8 rll toilet paper",
        "price": 3.35,
        "tags": [
          "toilet-paper"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.14863100862508977,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.09128850122521975,
        "field": "category",
        "feature": "111"
      }
    },
    {
      "offset": 10,
      "testCase": {
        "category": "115",
        "cost": 1.183,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410402010318",
        "name": "Pirkka tuna fish pieces in oil 200g/150g",
        "price": 1.69,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.14348024636645532,
        "field": "category",
        "feature": "103"
      }
    }
  ],
  "accurateCases": [
    {
      "offset": 2,
      "testCase": {
        "category": "101",
        "cost": 0.903,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6413467282508",
        "name": "Fazer Puikula fullcorn rye bread 330g",
        "price": 1.29,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9836065573770494,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.9836065573770494,
        "field": "category",
        "feature": "101"
      }
    },
    {
      "offset": 4,
      "testCase": {
        "category": "103",
        "cost": 1.393,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6412000030026",
        "name": "Saarioinen Maksalaatikko liver casserole 400g",
        "price": 1.99,
        "tags": [
          "meat",
          "food"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.141419991195898,
        "field": "category",
        "feature": "103"
      },
      "correct": {
        "$p": 0.141419991195898,
        "field": "category",
        "feature": "103"
      }
    },
    {
      "offset": 5,
      "testCase": {
        "category": "104",
        "cost": 0.567,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "6410405082657",
        "name": "Pirkka Finnish semi-skimmed milk 1l",
        "price": 0.81,
        "tags": [
          "lactose",
          "drink",
          "pirkka"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9721508335126348,
        "field": "category",
        "feature": "104"
      },
      "correct": {
        "$p": 0.9721508335126348,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 6,
      "testCase": {
        "category": "104",
        "cost": 1.365,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6408430000258",
        "name": "Valio eila™ Lactose-free semi-skimmed milk drink 1l",
        "price": 1.95,
        "tags": [
          "lactose-free",
          "drink"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.6242204303115763,
        "field": "category",
        "feature": "104"
      },
      "correct": {
        "$p": 0.6242204303115763,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 7,
      "testCase": {
        "category": "108",
        "cost": 2.415,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6420101441542",
        "name": "Kulta Katriina filter coffee 500g",
        "price": 3.45,
        "tags": [
          "coffee"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.9762803781616086,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.9762803781616086,
        "field": "category",
        "feature": "108"
      }
    },
    {
      "offset": 8,
      "testCase": {
        "category": "109",
        "cost": 1.533,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6411401015090",
        "name": "Fazer Sininen milk chocolate slab 200g",
        "price": 2.19,
        "tags": [
          "candy",
          "lactose"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.33912840860958743,
        "field": "category",
        "feature": "109"
      },
      "correct": {
        "$p": 0.33912840860958743,
        "field": "category",
        "feature": "109"
      }
    }
  ],
  "errorCases": [
    {
      "offset": 0,
      "testCase": {
        "category": "100",
        "cost": 0.1,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "2000818700008",
        "name": "Pirkka banana",
        "price": 0.166,
        "tags": [
          "fresh",
          "fruit",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1295991145436842,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.11857669800109355,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 1,
      "testCase": {
        "category": "100",
        "cost": 0.774,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6410405093677",
        "name": "Pirkka iceberg salad Finland 100g 1st class",
        "price": 1.29,
        "tags": [
          "fresh",
          "vegetable",
          "pirkka",
          "salad"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1295991145436842,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.11857669800109355,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 3,
      "testCase": {
        "category": "102",
        "cost": 1.953,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410405205483",
        "name": "Pirkka Finnish beef-pork minced meat 20% 400g",
        "price": 2.79,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.1439259526572726,
        "field": "category",
        "feature": "103"
      },
      "correct": {
        "$p": 0.08785487117032287,
        "field": "category",
        "feature": "102"
      }
    },
    {
      "offset": 9,
      "testCase": {
        "category": "111",
        "cost": 2.345,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6413200330206",
        "name": "Lotus Soft Embo 8 rll toilet paper",
        "price": 3.35,
        "tags": [
          "toilet-paper"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.14863100862508977,
        "field": "category",
        "feature": "108"
      },
      "correct": {
        "$p": 0.09128850122521975,
        "field": "category",
        "feature": "111"
      }
    },
    {
      "offset": 10,
      "testCase": {
        "category": "115",
        "cost": 1.183,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410402010318",
        "name": "Pirkka tuna fish pieces in oil 200g/150g",
        "price": 1.69,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.14348024636645532,
        "field": "category",
        "feature": "103"
      }
    }
  ],
  "alpha_binByTopScore": [
    {
      "meanScore": 0.13602461666243043,
      "maxScore": 0.14348024636645532,
      "minScore": 0.1295991145436842,
      "accuracy": 0.25,
      "n": 4,
      "accurateOffsets": [
        4
      ],
      "errorOffsets": [
        0,
        1,
        10
      ]
    },
    {
      "meanScore": 0.3139764500508815,
      "maxScore": 0.6242204303115763,
      "minScore": 0.1439259526572726,
      "accuracy": 0.5,
      "n": 4,
      "accurateOffsets": [
        8,
        6
      ],
      "errorOffsets": [
        3,
        9
      ]
    },
    {
      "meanScore": 0.9773459230170976,
      "maxScore": 0.9836065573770494,
      "minScore": 0.9721508335126348,
      "accuracy": 1,
      "n": 3,
      "accurateOffsets": [
        5,
        7,
        2
      ],
      "errorOffsets": []
    }
  ]
}

Similarity

POST/api/v1/_similarity

Similarity can be used to return entries that are similar to a given sample object.

The sample object can be either a complete or a partial row. Similarity operation uses TF-IDF for scoring the documents.

The chapter Personalisation also explains a characteristic of the similarity model.

Guides

Example request

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In the example we're finding similar products to a given existing product. Aito assumes that the given sample object is a hypothetical new object, which is why in this example the exact same product is also in the results.

Request body

{
  "from": "products",
  "similarity": {
    "category": "108",
    "id": "6411300000494",
    "name": "Juhla Mokka coffee 500g sj",
    "price": 3.95,
    "tags": [
      "coffee"
    ]
  },
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_similarity \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "similarity": {
      "category": "108",
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "price": 3.95,
      "tags": ["coffee"]
    },
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$score": 126.04566816298527,
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    },
    {
      "$score": 30.33799469334562,
      "category": "108",
      "cost": 2.765,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6411300164653",
      "name": "Juhla Mokka Dark Roast coffee 500g hj",
      "price": 3.95,
      "tags": [
        "coffee"
      ]
    },
    {
      "$score": 5.3239876815300375,
      "category": "108",
      "cost": 2.415,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6420101441542",
      "name": "Kulta Katriina filter coffee 500g",
      "price": 3.45,
      "tags": [
        "coffee"
      ]
    }
  ]
}

Example request

In the example we're finding similar products based on just a product name.

Request body

{
  "from": "products",
  "similarity": {
    "name": "Hovis Seed Sensations Seven Seeds Original 800g"
  },
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_similarity \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "similarity": { "name": "Hovis Seed Sensations Seven Seeds Original 800g" },
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$score": 1,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$score": 1,
      "category": "100",
      "cost": 0.586,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "2000604700007",
      "name": "Cucumber Finland",
      "price": 0.9765,
      "tags": [
        "fresh",
        "vegetable"
      ]
    },
    {
      "$score": 1,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6410405060457",
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "tomato"
      ]
    }
  ]
}

Match

POST/api/v1/_match

Deprecated: This endpoint is deprecated. Use Predict instead, which now provides the same functionality with better performance and more features.


Match the most likely value/feature of a column or any column of a linked table to a given hypothesis.

Differences to Predict

While match is similar to Predict query, there are fine-grained differences explained below.

Predict returns features, while match can return values

Match can return A) the row behind a link or B) the value inside a text field. If match is done against a non-analyzed field, it works similarly to predict, except the inference algorithm is somewhat different.

The inference model is different

Predict treats features as 'black boxes', and it does statistical reasoning purely based on the feature's own statistics. Match does 'glass box' statistical reasoning by using all the features found behind the link or within a field.

For example, if you are predicting a product, the predict query will look at the history of each individual product ID. If there is no history for a product, Aito will not be able to do proper inference. On the other hand, if you are matching a product, Aito will look at the product's category, title, and description. This enables Aito to match products it has never seen before, as long as it is familiar with their internal features.

The chapter Personalisation also explains a characteristic of the matching.

Match user to products

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In the example we're matching a user to products.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "larry"
  },
  "match": "product",
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_match \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "larry" },
    "match": "product",
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.03636645071658641,
      "category": "100",
      "cost": 0.586,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "2000604700007",
      "name": "Cucumber Finland",
      "price": 0.9765,
      "tags": [
        "fresh",
        "vegetable"
      ]
    },
    {
      "$p": 0.03303793576204806,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$p": 0.03271082748717629,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6410405060457",
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "tomato"
      ]
    },
    {
      "$p": 0.03142380061919346,
      "category": "101",
      "cost": 1.295,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "6411402202208",
      "name": "Fazer Puikula fullcorn rye bread 9 pcs/500g",
      "price": 1.85,
      "tags": [
        "gluten",
        "bread"
      ]
    },
    {
      "$p": 0.029923824657771932,
      "category": "100",
      "cost": 0.168,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "2000503600002",
      "name": "Chiquita banana",
      "price": 0.28054,
      "tags": [
        "fresh",
        "fruit"
      ]
    }
  ]
}

Relate

POST/api/v1/_relate

Relate provides statistical information of data relationships.

It calculates correlations between pairs of features, which can be used to find causation and correlation patterns.

The hits are by default ordered by relation.mi field. It indicates how strong the correlation is.

See in action

What features of products affect purchasing

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

In the example we ask Aito to explain what factors of products affect to people purchasing them. With $exists, we tell Aito to get all properties of the product (impressions table links to the products table), and relate those to the condition {"purchase": true }.

The response may seem overwhelming but it contains a lot of useful information.

When looking at the second hit, we can see that when { "product.tags" : { "$has": "vegetable" } }, the "lift" value is high (compared to 1.0). It means that when the product tags contain a tag vegetable, it is ~1.9x more likely that the product will be purchased compared to the average product (=base probability).

The lift is calculated with the formula: the probability of the condition { "purchase": true} divided by the average probability of the condition. The formula with the correct field names is: ps.pOnCondition / ps.p.

In the example data set, people purchase 50% of products they see. This causes the base probability to be 0.5.

Request body

{
  "from": "impressions",
  "where": {
    "$exists": "product"
  },
  "relate": [
    {
      "purchase": true
    }
  ],
  "limit": 2
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_relate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "$exists": "product" },
    "relate": [
      { "purchase": true }
    ],
    "limit": 2
  }'

Response

{
  "offset": 0,
  "total": 2,
  "hits": [
    {
      "related": {
        "purchase": {
          "$has": true
        }
      },
      "condition": {
        "product": {
          "$has": "6414880021620"
        }
      },
      "lift": 2.605499049669309,
      "fs": {
        "f": 4670,
        "fOnCondition": 277,
        "fOnNotCondition": 4393,
        "fCondition": 1942,
        "n": 90325
      },
      "ps": {
        "p": 0.05171211265734498,
        "pOnCondition": 0.1347358603851046,
        "pOnNotCondition": 0.049878526145411654,
        "pCondition": 0.02150105858141339
      },
      "info": {
        "h": 0.2936258448995185,
        "mi": 0.07177113445563739,
        "miTrue": 0.18614563870100148,
        "miFalse": -0.11437450424536409
      },
      "relation": {
        "n": 90325,
        "varFs": [
          1942,
          4670
        ],
        "stateFs": [
          83990,
          1665,
          4393,
          277
        ],
        "mi": 0.0015921013529465646
      }
    },
    {
      "related": {
        "purchase": {
          "$has": true
        }
      },
      "condition": {
        "product": {
          "$has": "2000818700008"
        }
      },
      "lift": 2.094767786770449,
      "fs": {
        "f": 4670,
        "fOnCondition": 334,
        "fOnNotCondition": 4336,
        "fCondition": 2928,
        "n": 90325
      },
      "ps": {
        "p": 0.05171211265734498,
        "pOnCondition": 0.10832486778045067,
        "pOnNotCondition": 0.04980608417411301,
        "pCondition": 0.03241722829479578
      },
      "info": {
        "h": 0.2936258448995185,
        "mi": 0.03637299371591339,
        "miTrue": 0.11555992083809466,
        "miFalse": -0.07918692712218127
      },
      "relation": {
        "n": 90325,
        "varFs": [
          2928,
          4670
        ],
        "stateFs": [
          83061,
          2594,
          4336,
          334
        ],
        "mi": 0.0012314338238000682
      }
    }
  ]
}

Generic query

POST/api/v1/_query

Generic query is a powerful expert interface.

It provides the functionality of every other query type in the API. Search, Similarity, Match, and Recommend can be seen as convenience APIs for the generic query.

The query format resembles the Search-query, except that it supports a "get" statement. Since this endpoint provides functionality of all other queries, "get": "product" is used as a replacement for "predict": "product", "recommend": "product", and "match": "product" counterparts.

The chapter Personalisation also explains a characteristic of the inference model.

Namespace shifting of "get"

The "get" operation changes the namespaces of "select" and "orderBy" operations. The namespace is changed from the "from" table to the linked table (specified with "get").

As an example, think of this query. The impressions table has a column called product which links to a row in products table. The price and title fields are columns of products.

{
  "from": "impressions",
  "where": {
    "query": "macbook air 2018"
  },
  "get": "product",
  "orderBy": ["price"],
  "select": ["title", "$highlight"]
}

When using "select" and "orderBy", we are already in the products table namespace, instead of having to use product.title or product.price.

Related information

Search query

Simple search query with the generic query.

Request body

{
  "from": "products",
  "where": {
    "id": "6410402010318"
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": { "id": "6410402010318" }
  }'

Response

{
  "offset": 0,
  "total": 1,
  "hits": [
    {
      "category": "115",
      "cost": 1.183,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6410402010318",
      "name": "Pirkka tuna fish pieces in oil 200g/150g",
      "price": 1.69,
      "tags": [
        "meat",
        "food",
        "protein",
        "pirkka"
      ]
    }
  ]
}

Search query with highlighted results

Search query which returns related products ordered by similarity. The response also contains the highlighted words which matched to the search term.

Request body

{
  "from": "products",
  "where": {
    "name": {
      "$match": "coffee"
    }
  },
  "select": [
    "id",
    "name",
    "tags",
    "price",
    "$score",
    "$highlight"
  ],
  "orderBy": "$similarity"
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "name": { "$match": "coffee" }
    },
    "select": ["id", "name", "tags", "price", "$score", "$highlight"],
    "orderBy": "$similarity"
  }'

Response

{
  "offset": 0,
  "total": 4,
  "hits": [
    {
      "id": "6411300000494",
      "name": "Juhla Mokka coffee 500g sj",
      "tags": [
        "coffee"
      ],
      "price": 3.95,
      "$score": 2.1726635013471625,
      "$highlight": [
        {
          "score": 1.1194647495169912,
          "field": "name",
          "highlight": "Juhla Mokka <font color=\"green\">coffee</font> 500g sj"
        }
      ]
    },
    {
      "id": "6420101441542",
      "name": "Kulta Katriina filter coffee 500g",
      "tags": [
        "coffee"
      ],
      "price": 3.45,
      "$score": 2.1726635013471625,
      "$highlight": [
        {
          "score": 1.1194647495169912,
          "field": "name",
          "highlight": "Kulta Katriina filter <font color=\"green\">coffee</font> 500g"
        }
      ]
    },
    {
      "id": "6411300164653",
      "name": "Juhla Mokka Dark Roast coffee 500g hj",
      "tags": [
        "coffee"
      ],
      "price": 3.95,
      "$score": 2.1726635013471625,
      "$highlight": [
        {
          "score": 1.1194647495169912,
          "field": "name",
          "highlight": "Juhla Mokka Dark Roast <font color=\"green\">coffee</font> 500g hj"
        }
      ]
    },
    {
      "id": "6410405181190",
      "name": "Pirkka Costa Rica filter coffee 500g UTZ",
      "tags": [
        "coffee",
        "pirkka"
      ],
      "price": 2.89,
      "$score": 2.1726635013471625,
      "$highlight": [
        {
          "score": 1.1194647495169912,
          "field": "name",
          "highlight": "Pirkka Costa Rica filter <font color=\"green\">coffee</font> 500g UTZ"
        }
      ]
    }
  ]
}

Generic similarity query

In the example we're finding similar products based on the given hypothetical new product name.

Request body

{
  "from": "products",
  "orderBy": {
    "$similarity": {
      "name": "Atria bratwurst 175g"
    }
  },
  "limit": 2
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "orderBy": {
      "$similarity": { "name": "Atria bratwurst 175g" }
    },
    "limit": 2
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$score": 2.1455611831385513,
      "category": "102",
      "cost": 0.623,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6407870070333",
      "name": "Atria lauantaimakkara bread sausage 225g",
      "price": 0.89,
      "tags": [
        "meat",
        "sausage",
        "with-bread"
      ]
    },
    {
      "$score": 2.1455611831385513,
      "category": "102",
      "cost": 1.225,
      "googleClicks": 8,
      "googleImpressions": 100,
      "id": "6407870071224",
      "name": "Atria Gotler ham sausage 300g",
      "price": 1.75,
      "tags": [
        "meat",
        "sausage",
        "with-bread"
      ]
    }
  ]
}

Generic predict query

In the example we're predicting which tags a new hypothetical product could have.

Request body

{
  "from": "products",
  "where": {
    "name": "Atria bratwurst 175g"
  },
  "get": "tags.$feature",
  "orderBy": "$p",
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": { "name": "Atria bratwurst 175g" },
    "get": "tags.$feature",
    "orderBy": "$p",
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 25,
  "hits": [
    {
      "$p": 0.6261782668084108,
      "field": "tags",
      "feature": "sausage"
    },
    {
      "$p": 0.1088078480566381,
      "field": "tags",
      "feature": "meat"
    },
    {
      "$p": 0.033036915535851454,
      "field": "tags",
      "feature": "food"
    },
    {
      "$p": 0.02033040956052397,
      "field": "tags",
      "feature": "gluten"
    },
    {
      "$p": 0.02033040956052397,
      "field": "tags",
      "feature": "protein"
    }
  ]
}

Recommend products which a customer would most likely purchase

In the example we're finding the top 5 products which veronica (user id) would most likely to purchase based on her behavior history stored in impressions table.

This example is the the same as in the documentation of Recommendation endpoint, but made with the generic query.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "veronica"
  },
  "get": "product",
  "orderBy": {
    "$p": {
      "$context": {
        "purchase": true
      }
    }
  },
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "veronica" },
    "get": "product",
    "orderBy": {
      "$p": {
        "$context": { "purchase": true }
      }
    },
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.19266411598455546,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6410405093677",
      "name": "Pirkka iceberg salad Finland 100g 1st class",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "salad"
      ]
    },
    {
      "$p": 0.16679522498673674,
      "category": "100",
      "cost": 0.586,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "2000604700007",
      "name": "Cucumber Finland",
      "price": 0.9765,
      "tags": [
        "fresh",
        "vegetable"
      ]
    },
    {
      "$p": 0.161778166328556,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$p": 0.13527444193705185,
      "category": "100",
      "cost": 0.168,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "2000503600002",
      "name": "Chiquita banana",
      "price": 0.28054,
      "tags": [
        "fresh",
        "fruit"
      ]
    },
    {
      "$p": 0.11674813114595652,
      "category": "111",
      "cost": 1.61,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6414880021620",
      "name": "Ilta Sanomat weekend news",
      "price": 2.3,
      "tags": [
        "news"
      ]
    }
  ]
}

Query with custom scoring

In the example we're finding the top 5 products which veronica (user id) would most likely to purchase but in addition we're boosting products which have higher price. This would recommend products which are relevant for the user but also bring higher revenue to the shop. This demonstrates a situation where multiple factors should be considered in recommendations.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "veronica"
  },
  "get": "product",
  "orderBy": {
    "$multiply": [
      {
        "$p": {
          "$context": {
            "purchase": true
          }
        }
      },
      "price"
    ]
  },
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "veronica" },
    "get": "product",
    "orderBy": {
      "$multiply": [
        {
          "$p": {
            "$context": { "purchase": true }
          }
        },
        "price"
      ]
    },
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$score": 0.28486899671784605,
      "category": "111",
      "cost": 2.345,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "6413200330206",
      "name": "Lotus Soft Embo 8 rll toilet paper",
      "price": 3.35,
      "tags": [
        "toilet-paper"
      ]
    },
    {
      "$score": 0.26852070163569997,
      "category": "111",
      "cost": 1.61,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6414880021620",
      "name": "Ilta Sanomat weekend news",
      "price": 2.3,
      "tags": [
        "news"
      ]
    },
    {
      "$score": 0.24853670962007654,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "6410405093677",
      "name": "Pirkka iceberg salad Finland 100g 1st class",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "salad"
      ]
    }
  ]
}

Batch

POST/api/v1/_batch

Batch query operation.

Allows you to send multiple queries in a single request. Batch query takes an array of queries and returns an array of results. Each query can be one of the following types:

Batch query can be used for example to request predictions for multiple fields on the same go and request similar items for a reference.

Predict category and tags, and also fetch similar products for reference

You can copy-paste the example curl command to your terminal.

Request body

[
  {
    "from": "products",
    "where": {
      "name": "rye bread"
    },
    "predict": "category"
  },
  {
    "from": "products",
    "where": {
      "name": "rye bread"
    },
    "predict": "tags",
    "exclusiveness": false
  },
  {
    "from": "products",
    "similarity": {
      "name": "rye bread"
    }
  }
]

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_batch \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  [
    {
      "from": "products",
      "where": { "name": "rye bread" },
      "predict": "category"
    },
    {
      "from": "products",
      "where": { "name": "rye bread" },
      "predict": "tags",
      "exclusiveness": false
    },
    {
      "from": "products",
      "similarity": { "name": "rye bread" }
    }
  ]'

Response

[
  {
    "offset": 0,
    "total": 11,
    "hits": [
      {
        "$p": 0.9836065573770494,
        "field": "category",
        "feature": "101"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "100"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "102"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "103"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "104"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "106"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "107"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "108"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "109"
      },
      {
        "$p": 0.0016393442622950841,
        "field": "category",
        "feature": "111"
      }
    ]
  },
  {
    "offset": 0,
    "total": 25,
    "hits": [
      {
        "$p": 0.9980622988064398,
        "field": "tags",
        "feature": "bread"
      },
      {
        "$p": 0.99713317955023,
        "field": "tags",
        "feature": "gluten"
      },
      {
        "$p": 0.13092336616076747,
        "field": "tags",
        "feature": "pirkka"
      },
      {
        "$p": 0.11459488902123804,
        "field": "tags",
        "feature": "food"
      },
      {
        "$p": 0.09780018271375573,
        "field": "tags",
        "feature": "meat"
      },
      {
        "$p": 0.07188145376592844,
        "field": "tags",
        "feature": "protein"
      },
      {
        "$p": 0.0630754664342347,
        "field": "tags",
        "feature": "drink"
      },
      {
        "$p": 0.0630754664342347,
        "field": "tags",
        "feature": "lactose"
      },
      {
        "$p": 0.0541958410478779,
        "field": "tags",
        "feature": "fresh"
      },
      {
        "$p": 0.04524754379763742,
        "field": "tags",
        "feature": "candy"
      }
    ]
  },
  {
    "offset": 0,
    "total": 42,
    "hits": [
      {
        "$score": 2.967681932293201,
        "category": "101",
        "cost": 1.183,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "6437002001454",
        "name": "VAASAN Ruispalat 660g 12 pcs fullcorn rye bread",
        "price": 1.69,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      {
        "$score": 2.967681932293201,
        "category": "101",
        "cost": 1.295,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6411402202208",
        "name": "Fazer Puikula fullcorn rye bread 9 pcs/500g",
        "price": 1.85,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      {
        "$score": 2.967681932293201,
        "category": "101",
        "cost": 0.945,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6408180733260",
        "name": "Vaasan Ruispalat thin sliced rye bread 6pcs/195g",
        "price": 1.35,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      {
        "$score": 2.967681932293201,
        "category": "101",
        "cost": 0.903,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6413467282508",
        "name": "Fazer Puikula fullcorn rye bread 330g",
        "price": 1.29,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      {
        "$score": 2.967681932293201,
        "category": "101",
        "cost": 0.693,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6413466080204",
        "name": "Oululainen reissumies dark rye bread 4pcs/280g",
        "price": 0.99,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      {
        "$score": 1.6441207746609814,
        "category": "102",
        "cost": 0.623,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6407870070333",
        "name": "Atria lauantaimakkara bread sausage 225g",
        "price": 0.89,
        "tags": [
          "meat",
          "sausage",
          "with-bread"
        ]
      },
      {
        "$score": 1.6441207746609814,
        "category": "103",
        "cost": 1.043,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6409100024628",
        "name": "Breadded chicke nuggets 200g",
        "price": 1.49,
        "tags": [
          "meat",
          "food",
          "protein"
        ]
      },
      {
        "$score": 1,
        "category": "100",
        "cost": 0.1,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "2000818700008",
        "name": "Pirkka banana",
        "price": 0.166,
        "tags": [
          "fresh",
          "fruit",
          "pirkka"
        ]
      },
      {
        "$score": 1,
        "category": "100",
        "cost": 0.586,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "2000604700007",
        "name": "Cucumber Finland",
        "price": 0.9765,
        "tags": [
          "fresh",
          "vegetable"
        ]
      },
      {
        "$score": 1,
        "category": "100",
        "cost": 0.774,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410405060457",
        "name": "Pirkka bio cherry tomatoes 250g international 1lk",
        "price": 1.29,
        "tags": [
          "fresh",
          "vegetable",
          "pirkka",
          "tomato"
        ]
      }
    ]
  }
]

Aggregate

POST/api/v1/_aggregate

Aggregate operation.

Aggregate API is used to access aggregated values, like averages or sums. For example the following operation allows you to count all clicks by customer 4 and his mean click rate (ctr)

{
  "from": "impressions",
  "where": {
    "customer": 4
  },
  "aggregate": ["product.$sum", "product.$mean"]
}

Aggregate field can also calculate sums and averages of column scores as shown in the following example:

{
  "from": "products",
  "where": {
    "$knn": {
      "k": 4,
      "near": {
        "name": "Pirkka bread"
      }
    }
  },
  "aggregate": {
    "$mean": {
      "$freqP": {
        "f": "googleClicks",
        "n": "googleImpressions"
      }
    }
  }
}

The operation estimates the click-through-rate based on click and impression numbers using freqP, and then calculates the averages of the estimate.

Count amount of purchases and CTR of a product

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "impressions",
  "where": {
    "product.id": "6408180733260"
  },
  "aggregate": [
    "purchase.$sum",
    "purchase.$mean"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_aggregate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "product.id": "6408180733260" },
    "aggregate": ["purchase.$sum", "purchase.$mean"]
  }'

Response

{
  "purchase.$mean": 0.046141607000795545,
  "purchase.$mean.samples": 2514,
  "purchase.$mean.variance": 0.04401255910417968,
  "purchase.$mean.standardDeviation": 0.20979170408807798,
  "purchase.$mean.standardError": 0.004184134860196707,
  "purchase.$sum": 116,
  "purchase.$sum.samples": 2514
}

Count more statistics for product 6408180733260 with custom names

In the example, the entry count is named as 'impressions', purchase mean as 'conversion' and counts for searches, pre-fills and recommendations with more descriptive names.

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "impressions",
  "where": {
    "product.id": "6408180733260"
  },
  "aggregate": {
    "impressions": "$f",
    "purchases": "purchase.$sum",
    "conversion": "purchase.$mean",
    "searches": {
      "$f": {
        "context.type": "search"
      }
    },
    "prefills": {
      "$f": {
        "context.type": "prefill"
      }
    },
    "recommendations": {
      "$f": {
        "context.type": "recommendation"
      }
    }
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/_aggregate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "product.id": "6408180733260" },
    "aggregate": {
      "impressions": "$f",
      "purchases": "purchase.$sum",
      "conversion": "purchase.$mean",
      "searches": {
        "$f": { "context.type": "search" }
      },
      "prefills": {
        "$f": { "context.type": "prefill" }
      },
      "recommendations": {
        "$f": { "context.type": "recommendation" }
      }
    }
  }'

Response

{
  "recommendations": 0,
  "prefills": 69,
  "searches": 2292,
  "conversion": 0.046141607000795545,
  "conversion.samples": 2514,
  "conversion.variance": 0.04401255910417968,
  "conversion.standardDeviation": 0.20979170408807798,
  "conversion.standardError": 0.004184134860196707,
  "purchases": 116,
  "purchases.samples": 2514,
  "impressions": 2514
}

Create jobs

POST/api/v1/jobs/{query}

Create a job for queries that last longer than 30 seconds. The regular endpoints reach a timeout after 30 seconds.

You can make a job request out of Predict, Match, Similarity, Estimate, Generic, and Evaluate query endpoints. The query used is the same as you would use for the regular endpoint.

The API also supports running some of the more time-consuming database-operations as jobs. For the given operations, the jobs-API is the recommended way to call the API, due the query timeout limit. The available operations are Batch Data Insert, Data Delete, and Optimize endpoints. The payload format is identical to the regular operations.

Example request

I The examples are using the dataset of our grocery store demo app. To get deeper understanding of the data context, you can check out the demo app.

The example query is exactly the same as would be when using the regular _evaluate endpoint.

In the example we're evaluating how good results Aito provides when we predict category for a new hypothetical product. The results give us the accuracy and performance of the prediction example shown in Predict operation's documentation.

$index is a built-in variable which tells the insertion index of a row. In the example, we select 1/4 of the rows in products table to be used as test data. The rest of the rows are automatically used as training data.

Aito iterates through each product in the test data, and tests how accurate the prediction of category for a given product name was.

Request body

{
  "test": {
    "$index": {
      "$mod": [
        4,
        0
      ]
    }
  },
  "evaluate": {
    "from": "products",
    "where": {
      "name": {
        "$match": {
          "$get": "name"
        }
      }
    },
    "predict": "category"
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v1/jobs/_evaluate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "test": {
      "$index": {
        "$mod": [4, 0]
      }
    },
    "evaluate": {
      "from": "products",
      "where": {
        "name": {
          "$match": { "$get": "name" }
        }
      },
      "predict": "category"
    }
  }'

Response

{
  "id": "1cf6fa9b-385f-4e31-ad59-88150f14048a",
  "parameters": {},
  "path": "_evaluate",
  "startedAt": "2026-07-14T21:57:52.196811917Z"
}

Get status of all jobs

GET/api/v1/jobs/

List all jobs that exist currently.

Example request

Request

curl -X GET \
  https://shared.aito.ai/db/aito-demo/api/v1/jobs/ \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi'

Response

[
  {
    "id": "1cf6fa9b-385f-4e31-ad59-88150f14048a",
    "parameters": {},
    "path": "_evaluate",
    "startedAt": "2026-07-14T21:57:52.196811917Z"
  }
]

Get status of a job

GET/api/v1/jobs/{uuid}

If you have started a job for some of the queries, this endpoint can return you the status of the job by its ID.

Example request

Request

curl -X GET \
  https://shared.aito.ai/db/aito-demo/api/v1/jobs/1cf6fa9b-385f-4e31-ad59-88150f14048a \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi'

Response

{
  "id": "1cf6fa9b-385f-4e31-ad59-88150f14048a",
  "parameters": {},
  "path": "_evaluate",
  "startedAt": "2026-07-14T21:57:52.196811917Z"
}

Cancel a job

DELETE/api/v1/jobs/{uuid}

Cancel a running job by its ID.

The job is interrupted; long operations such as evaluate stop cooperatively and the job completes as cancelled. Cancelling a job that has already finished has no effect.

This is the way to stop a long-running asynchronous evaluation started with POST /api/v1/jobs/_evaluate.

Get result of a job

GET/api/v1/jobs/{uuid}/result

Get the query result for a created job.

Example request

Request

curl -X GET \
  https://shared.aito.ai/db/aito-demo/api/v1/jobs/1cf6fa9b-385f-4e31-ad59-88150f14048a/result \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi'

Response

null

Database API

Operations which manipulate the Aito database.

Get database schema

GET/api/v1/schema

Get the schema for the database.

Create database schema

PUT/api/v1/schema

Create or update the schema for the entire database.

Note:

  • An existing table that is not included in the updated schema will not be deleted.
  • An existing table that is included in the updated schema will be updated if the table has no data.
  • The new table names must be valid. See Valid Table Names section for more information.

See also: Schema Design Guide for data modeling patterns, type selection, and linking strategies.

Delete database

DELETE/api/v1/schema

Delete the entire database schema.

X The operation deletes all data and contents of the database! The action is irreversible.

Get table schema

GET/api/v1/schema/{table}

Get the schema of the specified table.

Create table schema

PUT/api/v1/schema/{table}

Update a schema of the specified table.

Note:

  • The table schema cannot be updated if it contains data.
  • The new table name must be valid. See Valid Table Names section for more information.

Delete table

DELETE/api/v1/schema/{table}

Delete a single table in the schema.

X The operation deletes all data and contents of the table! The action is irreversible.

Note: The delete operation would fail if it leaves the database schema in broken state.

For example, given the following schema:

{
  "schema": {
    "users": {
      "type": "table",
      "columns": {
        "username": { "type": "String" }
      }
    },
    "sessions" : {
      "type": "table",
      "columns": {
         "id"     : { "type" : "String" },
         "user"   : { "type" : "String", "link": "users.username" }
      }
    }
  }
}

The users table cannot be deleted before changing the sessions table first so that sessions.user is not linked to the users table.

Get column schema

GET/api/v1/schema/{table}/{column}

Get the schema of a column.

Add or replace column

PUT/api/v1/schema/{table}/{column}

Add or replace a column of a table.

X If a column with the same name already exists then the operation deletes all data and contents of the column! The action is irreversible.

Adding a column to a table that already has data

When you add a required (non-nullable) column to a table that already contains rows, you must provide a value to backfill the existing rows — otherwise the operation fails with "Column '…' cannot be null and needs a fill value for existing rows". Add the column and backfill in a single call:

{
  "type": "string",
  "value": "unassigned"
}

The value must match the column's type (a string for string/text, a number for int/decimal, a boolean for boolean, etc.). Every existing row gets that value; new rows can set their own.

Two ways to avoid needing a fill value:

  • make the column nullable{ "type": "string", "nullable": true } — existing rows get null;
  • add the column before loading data (on an empty table).

To later change those backfilled values per row, use _modify with an update + where (and upsert to insert when nothing matches).

Delete column

DELETE/api/v1/schema/{table}/{column}

Delete a column from a table.

X The operation deletes all data and contents of the column! The action is irreversible.

Note: The delete operation would fail if it leaves the database schema in broken state.

For example, given the following schema:

{
  "schema": {
    "users": {
      "type": "table",
      "columns": {
        "username": { "type": "String" },
        "name": { "type": "String" }
      }
    },
    "sessions" : {
      "type": "table",
      "columns": {
         "id"     : { "type" : "String" },
         "user"   : { "type" : "String", "link": "users.username" }
      }
    }
  }
}

The column username of the users table cannot be deleted before changing the sessions table first so that sessions.user is not linked to users.username.

Rename a table

POST/api/v1/schema/_rename

Rename a table to the specified name.

Rename the table in the 'from' field to the specified name in the rename field. Set 'replace' to true, if you want to replace an existing table with the specified name.

The new table name must be valid. See Valid Table Names section for more information.

Copy a table

POST/api/v1/schema/_copy

Copy a table. This operations creates a copy of the table with the given name. The operation can be very fast, because the copying is done by copying the reference to the underlying immutable data structure.

The 'from' field must contain the name of the copied table. The 'copy' field must contain the new name of the new copy. Set 'replace' field to true, if you want to replace any existing table with the target name.

The new table name must be valid. See Valid Table Names section for more information.

Insert entry

POST/api/v1/data/{table}

Insert entry to a table.

Insert multiple entries

POST/api/v1/data/{table}/batch

Import multiple entries into the database.

The batch import can be used to upload multiple entries to a single table. The payload needs to be a valid JSON array (instead of ndjson).

The batch import can run as a job. The path for running batch as a job is <pre>/api/v1/jobs/data/<TABLE>/batch</pre>.

Note: batch API supports max 10MB payloads.

Append semantics: this endpoint appends every row in the payload. It does not deduplicate by id or any other field. If the same row is sent twice (for example because a webhook outbox retried after a network blip), the table will contain two copies. For idempotent ingest from an at-least-once delivery source, use update ... upsert: true on _modify instead.

Modify data

POST/api/v1/data/_modify

The unified modify endpoint provides a single API for all data modification operations: INSERT, UPDATE, DELETE, OPTIMIZE, RENAME, COPY, and WARM.

Operation Types

INSERT Operation

Insert one or more documents into a table.

{
  "into": "table_name",
  "insert": { "field1": "value1", "field2": "value2" }
}

Or insert multiple documents at once:

{
  "into": "table_name",
  "insert": [
    { "field1": "value1" },
    { "field1": "value2" }
  ]
}

UPDATE Operation

Update documents that match a condition. Uses SQL-style syntax.

{
  "update": "table_name",
  "set": {
    "field_to_update": "new_value"
  },
  "where": {
    "field": "condition_value"
  }
}

The set clause specifies which fields to update and their new values. Only the specified fields are updated; other fields retain their existing values.

The where clause uses the same proposition syntax as search queries.

If the where clause matches zero rows, the operation is a no-op unless upsert is true — see below.

upsert: true — insert if no match found

When upsert is true, an UPDATE that matches zero rows inserts a single new row instead of being a no-op. The new row is built from the set clause merged with any top-level field-equality predicates harvested from where, so the canonical shape is:

{
  "update": "impressions",
  "where":  { "event_id": "evt_abc123" },
  "set":    { "user_id": "u_42", "product_id": "p_77", "ts": 1714500000 },
  "upsert": true
}

On first delivery the new row holds event_id: "evt_abc123" (harvested from where) plus the three fields from set. On replay, where matches the existing row, the update path runs, and the skip-if-equal optimization short-circuits the segment rewrite when every set value already matches — making upsert replays effectively no-ops.

Behavior:

  • The match is by where predicate, not by primary key (Aito has no primary-key concept). Use a high-cardinality field as the key so the match is unambiguous.
  • The harvest only handles top-level { field: literal } shapes. If you use operators ($gt, $has, $or, etc.) in where, the harvest returns nothing and you must include every required field directly in set.
  • The reported total is 1 for an inserted row, or the matched row count for an updated row.

This is the recommended API for idempotent ingest from a webhook outbox or any other at-least-once delivery source.

DELETE Operation

Delete documents that match a condition.

{
  "from": "table_name",
  "delete": {
    "field": "condition_value"
  }
}

OPTIMIZE Operation

Optimize a table's storage for better query performance.

{
  "optimize": "table_name"
}

RENAME Operation

Rename a table to a new name.

{
  "from": "old_table_name",
  "rename": "new_table_name"
}

Use "replace": true to overwrite an existing table with the same name:

{
  "from": "source_table",
  "rename": "target_table",
  "replace": true
}

COPY Operation

Create a copy of a table. This is typically a fast operation because copies share the underlying immutable data structures.

{
  "from": "source_table",
  "copy": "destination_table"
}

Use "replace": true to overwrite an existing table:

{
  "from": "source_table",
  "copy": "destination_table",
  "replace": true
}

WARM Operation

Execute queries for cache warming without returning results. This is useful for keeping the database responsive after write operations by pre-computing query results before they are needed.

{
  "warm": [
    {"from": "products", "predict": "category"},
    {"from": "products", "recommend": "related_product"}
  ]
}

The warm operation accepts an array of queries using the same syntax as the _batch endpoint. Query results are discarded - this operation is purely for its side effects on internal caches.

Common use case: Atomic write-then-warm to keep the database responsive:

{
  "operations": [
    {"into": "products", "insert": {"id": 123, "name": "New Product"}},
    {"optimize": "products"},
    {"warm": [{"from": "products", "predict": "category"}]}
  ]
}

See Warming Strategies for advanced usage patterns including write/read table separation.

Batch Operations

Execute multiple operations atomically in a single request.

{
  "operations": [
    { "into": "table_name", "insert": { "id": 1, "name": "Item" } },
    { "update": "table_name", "set": { "status": "active" }, "where": { "id": 1 } },
    { "from": "table_name", "delete": { "status": "deleted" } },
    { "from": "old_table", "copy": "backup_table" }
  ]
}

Alternatively, operations can be provided as a JSON array at the top level:

[
  { "into": "table_name", "insert": { "id": 1 } },
  { "optimize": "table_name" }
]

Response

Each operation returns a result indicating the outcome:

  • INSERT: { "total": <number_of_inserted_rows> }
  • UPDATE: { "total": <number_of_updated_rows> }
  • DELETE: { "total": <number_of_deleted_rows> }
  • OPTIMIZE: { }
  • RENAME: { }
  • COPY: { }
  • WARM: { } (queries are executed but results are discarded)
  • Batch operations: { "results": [...] } with results for each operation

Idempotent ingest from an at-least-once event source

When ingesting from a webhook outbox, message queue, or any other at-least-once delivery source, the same event may arrive twice. The bulk insert endpoints (/api/v1/data/{table}/batch, /api/v1/data/{table}/stream) are append-only and do not deduplicate, so a retry of the same payload produces duplicate rows.

The recommended pattern is update ... upsert: true, keyed on a stable event id. Each retry is naturally idempotent: first delivery inserts the row, subsequent deliveries update it (or no-op if values are unchanged).

{
  "operations": [
    { "update": "impressions",
      "where":  { "event_id": "evt_abc123" },
      "set":    { "user_id": "u_42", "product_id": "p_77", "ts": 1714500000 },
      "upsert": true },
    { "update": "impressions",
      "where":  { "event_id": "evt_abc124" },
      "set":    { "user_id": "u_43", "product_id": "p_78", "ts": 1714500001 },
      "upsert": true }
  ]
}

Practical guidance:

  • Make the where key (event_id above) a high-cardinality field. The where evaluation hits the per-column index, so equality lookups are effectively O(1).
  • Cap the number of operations per request so the JSON payload stays under the 10MB limit (a few thousand upserts comfortably).
  • This pattern requires the source to attach a stable id to every payload. If the upstream system does not provide one, derive a deterministic key from the natural identifiers (e.g. order_id + line_item_id).

Alternative: delete + insert (for non-trivial where)

When the harvest can't read the natural key out of where (because you're using operators like $has, $or, or a compound predicate), you can fall back to an explicit delete + insert pair inside the same operations array. The pair is atomic, so it gives the same idempotency guarantee:

{
  "operations": [
    { "from": "impressions", "delete": { "event_id": "evt_abc123" } },
    { "into": "impressions",
      "insert": { "event_id": "evt_abc123", "user_id": "u_42",
                  "product_id": "p_77", "ts": 1714500000 } }
  ]
}

The trade-off is one extra operation per event and a re-tokenization of indexed text fields on every replay, so prefer the upsert form when it fits.

Notes

  • All operations are atomic - either all changes are applied or none are.
  • The UPDATE operation only modifies fields specified in the set clause.
  • An UPDATE that matches zero rows is a no-op unless upsert: true is set, in which case a new row is inserted from set plus equality keys harvested from where.
  • Replays of update ... upsert: true are cheap: when every set value already matches the existing row, the segment rewrite is skipped.
  • RENAME and COPY operations work on entire tables, not individual rows.
  • COPY is efficient because it shares data with the source table (copy-on-write).
  • For large batch inserts, consider using the streaming batch endpoint for better performance.

Delete entries

POST/api/v1/data/_delete

Delete entries with a Search-like interface.

You can describe the target table and filters for which entries to delete. The delete-operation must walk over each entry in the table, and can thus be expensive. Delete can be run as a job, thus preventing timeout errors from happening. The path for running delete as a job is <pre>/api/v1/jobs/data/<TABLE_NAME>/_delete</pre>.

! An empty proposition will match and delete everything!

Initiate file upload

POST/api/v1/data/{table}/file

Initiate a file upload session.

The file API allows circumventing the batch upload API payload size limit by allowing upload of large data sets. The file API accepts data in gzip compressed ndjson format, stored into a file.

! File must be a gzip compressed ndjson, normal JSON arrays are not accepted.

The data file is uploaded to AWS S3 and processed asynchronously. The file must be compressed with gzip before uploading to reduce the size of the transferred data.

The file API is not a single call, but requires a minimum of three requests (per table):

  1. Initiate - Call this endpoint to get a pre-signed S3 URL
  2. Upload - Upload your compressed ndjson file directly to S3 using the signed URL
  3. Trigger - Call the trigger endpoint to start processing
  4. Poll (optional) - Check the processing status until complete
┌────────┐          ┌──────┐          ┌────┐
│ Client │          │ Aito │          │ S3 │
└───┬────┘          └──┬───┘          └─┬──┘
    │  1. Initiate     │                │
    │─────────────────>│                │
    │  Pre-signed URL  │                │
    │<─────────────────│                │
    │                  │                │
    │  2. Upload file  │                │
    │───────────────────────────────────>
    │                  │                │
    │  3. Trigger      │                │
    │─────────────────>│                │
    │  "Started"       │   Get file     │
    │<─────────────────│───────────────>│
    │                  │   File data    │
    │                  │<───────────────│
    │                  │                │
    │  4. Poll status  │                │
    │─────────────────>│                │
    │  Status          │                │
    │<─────────────────│                │
    └──────────────────┴────────────────┘

You can find the bash implementation of the flow at our tools repository. See the upload-file.sh script.

Trigger file processing

POST/api/v1/data/{table}/file/{uuid}

Start the processing of a previously uploaded file.

Note: This operation is part of the file upload sequence. If you want to read how to execute a full file upload flow, see Initiate file upload documentation.

Get file processing status

GET/api/v1/data/{table}/file/{uuid}

Get the file upload progress.

The response is probabilistic and might not contain the very last result, since the status update is asynchronous, and the upload happens in multiple parallel streams. The response, however, will give an idea of approximate progress.

Note: This operation is part of the file upload sequence. If you want to read how to execute a full file upload flow, see Initiate file upload documentation.

Optimize the database

POST/api/v1/data/{table}/optimize

Optimize the database for the query performance

Note: The recommended way to run optimize is a job for it. The optimize-operation easily times out for any non-trivial database. The path for running optimize as a job is <pre>/api/v1/jobs/data/<TABLE_NAME>/optimize</pre>.

Aito.ai database is implemented as a log-structured merge-tree. Because this architecture, Aito's tables are implemented internally as a tree of table segments.

Now, the complexity of the table tree has major implications on both query speed and write speed side. The less segments Aito maintains in the tree, the faster the queries are, but the slower the writes are, because Aito needs to rewrite parts of the tree regularly. Similarly the more segments are allowed, the slower the queries are, but the faster the write speed becomes.

Aito seeks to maintain the approximately O(log N) segments in the table tree in order to maintain a reasonable compromise between the query and the write speeds.

Still, there can be situations, where it is beneficial to rewrite the entire database as a single segment to get the optimal query speed. Optimize operation does this.

It may take minutes or hours to optimize a big table. This means, that optimize should be used to improve the query performance only in situations, when the database and the results need to be updated rarely, for example nightly.

Optimize will maintain a write lock on the database over the entire operation. This means that you cannot add data at the time the optimize operation is running. Still, the queries will work normally. After the optimize is finished, the optimized table needs to be reloaded, which can induce a significant latency for the following query.

Guides

Database Schema

The Aito database requires a schema to operate. The schema defines:

  • The name of the tables
  • The name and the ColumnType of the columns in each table
  • The Analyzer of a column if needed
  • The relationships between tables

For schema design patterns and best practices, see the Schema Design Guide.

UserDefinedTableSchema

UserDefinedTableSchema

Availability: API v1

Any schema which is a valid Aito table schema.

Table schema describes the structure of the table in a formal language. The schema describes all fields (or columns), data types of the fields, and information to help Aito preprocess your data. For example what language a textual data contains.

The contents of the schema depends on the data that will be inserted into the database.

Format

{
  "type": string,
  "columns": object
}

Referenced in

Example

{
  "type": "table",
  "columns": {
    "id": {
      "type": "Int",
      "nullable": false
    },
    "name": {
      "type": "String",
      "nullable": false
    },
    "price": {
      "type": "Decimal",
      "nullable": false
    },
    "description": {
      "type": "Text",
      "nullable": false,
      "analyzer": "English"
    }
  }
}

UserDefinedObject

Availability: API v1 · API v2 (beta)

Any object which is valid according to the database schema.

The contents of the object depends on the data inserted into the database. If for example you have a products table which has fields name and price, your object could look like:

{ "name": "My product", "price": 172.19 }

Referenced in

Example

{
  "name": "My product",
  "price": 172.19
}

ColumnType

BooleanType

Availability: API v1

Boolean column type.

When column is a boolean, the only accepted values are true and false.

Format

{
  "type": string,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "boolean"
}

DecimalType

Availability: API v1

Double-precision floating-point number.

Format

{
  "type": string,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "Decimal",
  "nullable": false
}

IntType

Availability: API v1

Integer column type.

Format

{
  "type": string,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "Int"
}

StringType

Availability: API v1

String column type.

The string data type is a primitive version of the Text type. The value is turned into a single feature. For example "lazy black cat" becomes 1 feature: "lazy black cat".

Format

{
  "type": string,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "String",
  "nullable": false
}

TextType

Availability: API v1

Text column type.

The text data type enables smart textual analysis of strings. A text column has an analyzer which defines how the text can be split into words or tokens, which are used as features during inference.

Format

{
  "type": string,
  "analyzer": Analyzer,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "Text",
  "analyzer": "English",
  "nullable": false
}

JsonType

Availability: API v1

Json column type.

The json datatype type can have an arbitrary json value The value is turned into a single feature. For example {"a":[1, 2, 3], "b":true} becomes 1 feature: {"a":[1, 2, 3], "b":true}.

Format

{
  "type": string,
  "nullable": boolean,
  "link": string
}

Referenced in

Example

{
  "type": "Json",
  "nullable": false
}

ArrayType

Availability: API v1

Array column type.

The array data type allows storing lists of values of the same type. Each element in the array becomes a separate feature, enabling queries that match any element in the array.

Syntax

Array types are specified by appending [] to the base type name:

  • Int[] - Array of 32-bit integers
  • Long[] - Array of 64-bit integers
  • Decimal[] - Array of decimal numbers
  • String[] - Array of strings
  • Boolean[] - Array of booleans

Schema Example

{
  "schema": {
    "products": {
      "type": "table",
      "columns": {
        "id": { "type": "Int" },
        "name": { "type": "String" },
        "tags": { "type": "String[]" },
        "prices": { "type": "Decimal[]" },
        "ratings": { "type": "Int[]" }
      }
    }
  }
}

Data Example

{
  "id": 1,
  "name": "Laptop",
  "tags": ["electronics", "computer", "portable"],
  "prices": [999.99, 899.99, 849.99],
  "ratings": [5, 4, 5, 4, 3]
}

Querying Arrays

Direct Array Match

When querying array fields, you can provide an array of values to match. This matches rows where the array field contains all the specified values:

{
  "from": "products",
  "where": {
    "tags": ["electronics", "computer"]
  }
}

This query matches products where the tags array contains both "electronics" AND "computer".

Using $has Operator

The $has operator checks if an array contains a specific value:

{
  "from": "products",
  "where": {
    "tags": { "$has": "electronics" }
  }
}

This matches products where the tags array contains "electronics".

Using $match Operator

The $match operator matches arrays containing any of the specified values:

{
  "from": "products",
  "where": {
    "tags": { "$match": ["electronics", "clothing"] }
  }
}

This matches products where tags contains "electronics" OR "clothing".

Numeric Array Comparisons

For numeric arrays, comparison operators work element-wise. The condition matches if any element in the array satisfies the comparison:

{
  "from": "products",
  "where": {
    "prices": { "$lt": 900 }
  }
}

This matches products where any price in the array is less than 900.

You can also use arrays with comparison operators:

{
  "from": "products",
  "where": {
    "ratings": { "$gte": [4, 5] }
  }
}

Use Cases

  • Tags and categories: Store multiple labels per item
  • Multi-valued attributes: Store multiple values for a single field
  • Historical data: Store a series of measurements or values
  • Recommendations: Store lists of related items or preferences

Notes

  • Arrays can be nullable: use "nullable": true in the column definition
  • Empty arrays ([]) are valid values
  • Array elements must all be of the same type
  • When querying with an array value directly (e.g., "tags": ["a", "b"]), all values must match
  • The $has operator checks for a single value
  • The $match operator checks for any of multiple values

Format

{
  "type": string,
  "nullable": boolean
}

Referenced in

Example

{
  "type": "Int[]",
  "nullable": false
}

Analyzer

AliasAnalyzer

Availability: API v1

Aito has several built-in analyzers and they are selected by using their name in the "analyzer" field of a text column. For instance:

{ "analyzer": "english" }

The built-in analyzers include:

  • Standard Analyzer:
  • Name: "standard"
  • A good default analyzer which Works well in most languages. The analyzer generates features based on the Unicode Text Segmentation algorithm, as specified in Unicode Standard Annex #29. The standard analyzer filters English stop words that are normally not useful.
  • E.g: "the cats are running" will be break down into "cats", "running".
  • Whitespace Analyzer:
  • Name: "whitespace"
  • The analyzer breaks the text into features whenever it encounters a whitespace character. Adjacent sequences of non-Whitespace characters form tokens.
  • E.g: "the cats are running" will be break down into "the", "cats", "are", and "running".
  • Language Analyzer:
  • Alias: the language name or the language ISO 639-1 Code (except some special case)
  • A Language Analyzer with the default setting (no stop words or keywords).
  • See Language Analyzer for supported languages and its aliases.

Referenced in

CharNGramAnalyzer

Availability: API v1

The Character N-gram Analyzer breaks text into n-gram features.

For example, the following n-gram analyzer:

{ "type": "char-ngram", "minGram": 3, "maxGram": 3 }

would break the text "the cats are running" into the following list of features:

["the", "he ", "e c", " ca", "cat", "ats", "ts ", "s a", " ar", "are", "re ", "e r", " ru", "run", "unn", "nni", "nin", "ing"]

The analyzer can be useful for languages that don’t use spaces or that have long compound words, like German.

Format

{
  "type": string,
  "minGram": integer,
  "maxGram": integer
}

Referenced in

Example

{
  "type": "char-ngram",
  "minGram": 2,
  "maxGram": 3
}

DelimiterAnalyzer

Availability: API v1

The Delimiter Analyzer breaks text into features whenever encounters a specified delimiter character.

With the trimWhitespace option, the analyzer trims the whitespace surrounding a feature.

For example, the following analyzer:

{
  "type": "delimiter",
  "delimiter": ",",
  "trimWhitespace": true
}

would break the text "the, cats,are, running" into 4 features:

["the", "cats", "are", "running"]

Format

{
  "type": string,
  "delimiter": string,
  "trimWhitespace": boolean
}

Referenced in

LanguageAnalyzer

Availability: API v1

Language Analyzers aim to analyze text of a specific language.

When using a language analyzer, text is analyzed into lower-case word stem features. For example, using the following english analyzer:

{ "type": "language", "language": "english" }

a text "the cats are running" will be broken into 4 word stem features:

["the", "cat", "ar", "run"]

The value of the "language" parameter specifies which language will be used. The value can be the name or the ISO 639-1 code of the language. The full list is shown as below:

LanguageNameISO code
Arabicarabicar
Armenianarmenianhy
Basquebasqueeu
Brazilian Portuguesebrazilianpt-br
Bulgarianbulgarianbg
Catalancatalanca
Chinese, Japanese, Koreancjkcjk
Czechczechcs
Danishdanishda
Dutchdutchnl
Englishenglishen
Finnishfinnishfi
Frenchfrenchfr
Galiciangaliciangl
Germangermande
Greekgreekel
Hindihindihi
Hungarianhungarianhu
Indonesianindonesianid
Irishirishga
Italianitalianit
Latvianlatvianlv
Norwegiannorwegianno
Persianpersianfa
Portugueseportuguesept
Romanianromanianro
Russianrussianru
Spanishspanishes
Swedishswedishsv
Thaithaith
Turkishturkishtr

The language analyzers support filtering the stop words (common words that are normally not useful). Each language has a list of default stop words for filtering that can be enabled through the useDefaultStopWords" parameter. Some common English stop words are:

  "a", "an", "and", "are", "as", "at", "be", "but", "by", "for", 
  "if", "in", "into", "is", "it", "no", "not", "of", "on", "or", 
  "such", "that", "the", "their", "then", "there", "these", 
  "they", "this", "to", "was", "will", "with"

By default, "useDefaultStopWords" is set as false. The following analyzer:

{
  "type": "language",
  "language": "english",
  "useDefaultStopWords": true
}

would break the text "the cats are running" into 2 features:

["cat", "run"]

It is also possible to specify a set of words that would be filtered through the "customStopWords" parameter and a set of words that would not be analyzed through the "customKeyWords" parameter. The following analyzer:

{
  "type": "language",
  "language": "english",
  "useDefaultStopWords": false,
  "customStopWords": ["cats"],
  "customKeyWords": ["running"]
}

would break the text "the cats are running" into 3 features:

["the", "ar", "running"]

Format

{
  "type": string,
  "language": string,
  "useDefaultStopWords": boolean,
  "customStopWords": [string],
  "customKeyWords": [string]
}

Referenced in

TokenNGramAnalyzer

Availability: API v1

The Token N-gram Analyzer breaks text into token n-grams (shingles) based on a source analyzer. In other words, it combines the features of the source analyzer into new features.

For example, the following Token N-gram Analyzer:

{
  "type": "token-ngram",
  "source": "english",
  "minGram": 1,
  "maxGram": 2,
  "tokenSeparator": "_"
}

would breaks the text "the cat is running" into the following list of features:

["the", "the_cat", "cat", "cat_ar", "ar", "ar_run", "run"]

Format

{
  "type": string,
  "source": Analyzer,
  "minGram": integer,
  "maxGram": integer,
  "tokenSeparator": string
}

Referenced in

Multi-Tenant Instances

For self-hosted deployments, Aito supports multi-tenant mode where a single server hosts multiple isolated databases. Each tenant database has its own schema, data, and authentication configuration.

In multi-tenant mode, the server exposes two API namespaces:

  • /system/api/v1/* - System management API for administering databases
  • /db/{name}/api/v1/* - Individual database APIs (one per tenant)

The System Database

The system database contains a special db table that stores metadata about all tenant databases:

ColumnTypeDescription
nameStringDatabase name (required, used in URL path)
authJsonAuthentication configuration (required)
instanceIdStringOptional instance identifier
storeJsonOptional storage configuration
errorJsonError information if database failed to load

Authentication options:

  • { "type": "disabled" } - No authentication required
  • { "type": "apiKey", "readOnly": "key1", "readWrite": "key2" } - API key authentication

After creating a database, it becomes immediately accessible at /db/{name}/api/v1/*.

Contact support@aito.ai for self-hosted deployment documentation.

Get system schema:

curl -X GET \
  'http://localhost:9005/system/api/v1/schema' \
  -H 'x-api-key: your-system-api-key'

Create a database:

curl -X POST \
  'http://localhost:9005/system/api/v1/data/db' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: your-system-api-key' \
  -d '{
    "name": "my-database",
    "auth": { "type": "disabled" }
  }'

List databases:

curl -X POST \
  'http://localhost:9005/system/api/v1/_query' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: your-system-api-key' \
  -d '{ "from": "db" }'

Delete a database:

curl -X POST \
  'http://localhost:9005/system/api/v1/data/_delete' \
  -H 'Content-Type: application/json' \
  -H 'x-api-key: your-system-api-key' \
  -d '{
    "from": "db",
    "where": { "name": "my-database" }
  }'

Query language

The reference documentation for Aito query language.

Common concepts

Features

To make better analysis of the data, Aito splits fields into features under the hood. How the featurization is done, depends on the field type. For example the Text type supports an "analyzer" option which allows you to control how a text field is split into features.

Some queries, for example Relate, return the features instead of the actual values of the field.

Exclusiveness

Exclusiveness is an option in predictions. In summary, it describes whether the predicted field can have multiple values at the same time or not.

Understanding the concept is easiest through an example. If we were predicting tags for a product, we would want to set "exclusiveness": false, because a product can have multiple tags. A product could be described with the following tags:

However if we were predicting the user, who would most likely purchase a product, we would want to use "exclusiveness": true (default behavior) because the value can only be one user at a time.

$p vs $lift

If we were trying to find a customer, who is best characterized by a message, we'd need to understand the difference between $p and $lift. To make the difference clear, consider the following situation:

  • Alice messages often, but she doesn't mention iPhone often
  • Bob messages rarely, but only about iPhones

Querying users by $p quite likely finds Alice, because she may be overall the more likely person to mention "iPhone". Querying users by $lift, on the other hand will very certainly find Bob, because $lift describes that how characteristic the feature "iPhone" is for the user.

A more mathematical and technical description for the phenomenon is the following:

Aito uses Bayesian probability inference to estimate p(X|context) so that:

p(X|context) = p(X) × lift(X|context)

where the probability lift component is:

lift(X|context) = p(context|X) / p(context)

The probability lift component describes how much more likely X is true in the specified context, when compared to average.

In Aito query syntax: $p stands for the p(X|context), while $lift stands for the lift(X|context) component.

Text operators

Useful for creating conditional queries with text fields.

$match

Availability: API v1 · API v2 (beta) — v2 form: $match

Operator to check if a textual field fuzzy matches a given string.

Case insensitive. The matched text is split to tokens with the analyzer specified for the field in schema. For example { "$match": "great programmers" } will match strings "Bob is the greatest programmer!", and "Programmers are having great fun" if the field is properly analyzed with the English analyzer.

Format

{
  "$match": $toString or GetValueExpression or string
}

Referenced in

Example

{
  "$match": "coffee"
}

More examples

{
  "from": "products",
  "where": {
    "name": {
      "$match": "coffee"
    }
  }
}

$startsWith

Availability: API v1 · API v2 (beta) — v2 form: $startsWith

Operator to check if a textual field starts with a given string. Case sensitive.

Format

{
  "$startsWith": $toString or GetValueExpression or string
}

Referenced in

Example

{
  "$startsWith": "Cucumber"
}

More examples

{
  "from": "products",
  "where": {
    "name": {
      "$startsWith": "Cucumber"
    }
  }
}

Comparison operators

Useful for creating conditional queries.

$gt

Availability: API v1 · API v2 (beta) — v2 form: $gt

Operator to check if a field is greater than a given value.

Works with numeric types (Int, Decimal) and String fields (lexicographic comparison).

Syntax:

{ "fieldName": { "$gt": value } }

In a where clause:

{
  "from": "products",
  "where": {
    "price": { "$gt": 10.00 }
  }
}

This returns all products with a price greater than 10.00.

Format

{
  "$gt": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Referenced in

Example

{
  "$gt": 8
}

More examples

{
  "$gt": 231.1
}
{
  "$gt": "20150308"
}
{
  "from": "products",
  "where": {
    "price": {
      "$gt": 2.14
    }
  }
}

$gte

Availability: API v1 · API v2 (beta) — v2 form: $gte

Operator to check if a field is greater than or equal to a given value.

Works with numeric types (Int, Decimal) and String fields (lexicographic comparison).

Syntax:

{ "fieldName": { "$gte": value } }

In a where clause:

{
  "from": "products",
  "where": {
    "price": { "$gte": 5.00 }
  }
}

This returns all products with a price of 5.00 or higher.

Format

{
  "$gte": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Referenced in

Example

{
  "$gte": -2
}

More examples

{
  "$gte": 0
}
{
  "$gte": "20180502"
}
{
  "from": "products",
  "where": {
    "price": {
      "$gte": 2
    }
  }
}

$lt

Availability: API v1 · API v2 (beta) — v2 form: $lt

Operator to check if a field is less than a given value.

Works with numeric types (Int, Decimal) and String fields (lexicographic comparison).

Syntax:

{ "fieldName": { "$lt": value } }

In a where clause:

{
  "from": "products",
  "where": {
    "price": { "$lt": 3.00 }
  }
}

This returns all products with a price less than 3.00.

Format

{
  "$lt": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Referenced in

Example

{
  "$lt": 4
}

More examples

{
  "$lt": -12.1
}
{
  "$lt": "20180502"
}
{
  "from": "products",
  "where": {
    "price": {
      "$lt": 1.24
    }
  }
}

$lte

Availability: API v1 · API v2 (beta) — v2 form: $lte

Operator to check if a field is less than or equal to a given value.

Works with numeric types (Int, Decimal) and String fields (lexicographic comparison).

Syntax:

{ "fieldName": { "$lte": value } }

In a where clause:

{
  "from": "products",
  "where": {
    "price": { "$lte": 10.00 }
  }
}

This returns all products with a price of 10.00 or less.

Range queries:

Combine with $gte for range queries:

{
  "from": "products",
  "where": {
    "$and": [
      { "price": { "$gte": 5.00 } },
      { "price": { "$lte": 15.00 } }
    ]
  }
}

Format

{
  "$lte": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Referenced in

Example

{
  "$lte": 8
}

More examples

{
  "$lte": 0
}
{
  "$lte": "20180502"
}
{
  "from": "products",
  "where": {
    "price": {
      "$lte": 1
    }
  }
}

$has

Availability: API v1 · API v2 (beta) — v2 form: $has

Checks whether a field contains the specified feature (token).

$has is a low-level operation that works at the feature level. Features can differ significantly from the original data, especially for text fields when analyzers are used.

For example, if you have a field called content with the text "programmers and horses", the field would have features 'programmer' and 'hors' (stems produced by the English analyzer).

Syntax:

{ "fieldName": { "$has": "feature" } }

For Text fields:

{
  "from": "products",
  "where": {
    "description": { "$has": "coffee" }
  }
}

For array fields (String[]):

{
  "from": "products",
  "where": {
    "tags": { "$has": "organic" }
  }
}

This checks if the tags array contains the value "organic".

Difference from $match:

  • $has matches exact features (stemmed tokens for Text fields)
  • $match performs fuzzy text matching and handles multiple tokens

Use $has when you need precise feature matching, and $match for natural language search.

Format

{
  "$has": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Referenced in

Example

{
  "$has": "drink"
}

More examples

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "drink"
    }
  }
}

$defined

Availability: API v1 · API v2 (beta) — v2 form: $defined

Operator to filter rows based on whether a nullable field has a value or is null.

Syntax:

{ "fieldName": { "$defined": true } }
{ "fieldName": { "$defined": false } }

Find rows where field has a value:

{
  "from": "products",
  "where": {
    "discount": { "$defined": true }
  }
}

Find rows where field is null:

{
  "from": "products",
  "where": {
    "discount": { "$defined": false }
  }
}

This is useful for filtering out incomplete data or finding records with missing values.

Format

{
  "$defined": boolean
}

Referenced in

Example

{
  "$defined": true
}

$exists

Availability: API v1 · API v2 (beta) — v2 form: $exists

An operator to check if specific features exist in a field.

Syntax:

{ "$exists": "fieldName" }
{ "$exists": ["field1", "field2"] }

Check if a field has any features:

{
  "from": "products",
  "where": {
    "$exists": "tags"
  }
}

This returns rows where the tags field has at least one feature (non-empty).

Check multiple fields:

{
  "from": "products",
  "where": {
    "$exists": ["name", "category"]
  }
}

This returns rows where both name and category have features.

Format

{
  "$exists": PropositionSet
}

Referenced in

Example

{
  "$exists": [
    "query",
    "product.tags"
  ]
}

More examples

{
  "from": "impressions",
  "where": {
    "$on": [
      {
        "$exists": [
          "query",
          "customer.tags"
        ]
      },
      {
        "click": true
      }
    ]
  },
  "relate": [
    "product.title",
    "product.tags"
  ]
}

Logical operators

Useful for combining multiple conditions in conditional queries.

$and

Availability: API v1 · API v2 (beta) — v2 form: $and

Performs a logical and operation on the given array containing two or more Propositions.

  • With the non-inference query (e.g: Search, Similarity), the $and operator guarantees that all propositions are met. For instance, the following search query:
{
  "from": "products",
  "where": {
    "$and": [
      { "description": "super slim laptop" },
      { "price": { "$gt" : 200 } }
    ]
  }
}

will always find products of which description is super "slim laptop" and price is greater than 200

  • With the inference query (e.g: Predict, Match, Recommend), the $and operator does not guarantee that all propositions are met. For instance, the following predict query:
{
  "from": "products",
  "where": {
    "$and": [
      { "description": "super slim laptop" },
      { "price": { "$gt" : 200 } }
    ]
  },
  "price": "tag"
}
Aito might look for products with a price greater than 200 but do not match the description of super slim laptop or products that match the description but do not meet the price condition. This is because there might be a lack of data (e.g: not enough products in the price range) to make a sophisticated prediction.

To guarantee that all propositions are met in a inference query, refer to $atomic

Format

{
  "$and": [Proposition or PrimitiveProposition]
}

Referenced in

Example

{
  "$and": [
    {
      "$gt": 10
    },
    {
      "$lt": 20
    }
  ]
}

More examples

{
  "from": "products",
  "where": {
    "price": {
      "$and": [
        {
          "$gt": 1.5
        },
        {
          "$lt": 2.1
        }
      ]
    }
  }
}

$or

Availability: API v1 · API v2 (beta) — v2 form: $or

Performs a logical or operation on the given array containing two or more Propositions.

Format

{
  "$or": [Proposition or PrimitiveProposition]
}

Referenced in

Example

{
  "$or": [
    {
      "tags": "cover"
    },
    {
      "tags": "laptop"
    }
  ]
}

More examples

{
  "from": "products",
  "where": {
    "price": {
      "$or": [
        {
          "$lt": 0.9
        },
        {
          "$gt": 2.1
        }
      ]
    }
  }
}

$not

Availability: API v1 · API v2 (beta) — v2 form: $not

Performs a logical not operation on the given Proposition.

Format

{
  "$not": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "$not": {
    "tags": "laptop"
  }
}

More examples

{
  "$not": {
    "$lt": 0
  }
}
{
  "from": "products",
  "where": {
    "price": {
      "$not": {
        "$lt": 1.1
      }
    }
  }
}

Sort operators

Can be used in "orderBy" clause to declare the sorting order of the result.

$asc

Availability: API v1 · API v2 (beta) — v2 form: $asc

Sort returned hits in ascending order (A-Z) based on the given attribute or custom scoring function.

Format

{
  "$asc": Value
}

Referenced in

Example

{
  "$asc": "price"
}

More examples

{
  "$asc": "product.price"
}
{
  "$asc": {
    "$multiply": [
      "product.price",
      "$p"
    ]
  }
}

$asc(Relate)

Availability: API v1 · API v2 (beta) — v2 form: $asc

Sort returned hits in ascending order (A-Z) based on the given attribute (or column).

Format

{
  "$asc": string
}

Referenced in

Example

{
  "$asc": "lift"
}

$desc

Availability: API v1 · API v2 (beta) — v2 form: $desc

Sort returned hits in descending order (Z-A) based on the given attribute or custom scoring function.

Format

{
  "$desc": Value
}

Referenced in

Example

{
  "$desc": "price"
}

More examples

{
  "$desc": "product.price"
}
{
  "$desc": {
    "$multiply": [
      "product.price",
      "$p"
    ]
  }
}

$desc(Relate)

Availability: API v1 · API v2 (beta) — v2 form: $desc

Sort returned hits in descending (Z-A) order based on the given attribute (or column).

Format

{
  "$desc": string
}

Referenced in

Example

{
  "$desc": "info.miTrue"
}

Arithmetic operators

Can be used in conditional queries or scoring in "orderBy" clauses.

$mod

Availability: API v1 · API v2 (beta) — v2 form: $mod

Operator to check if the value of a field divided by a divisor has the specified remainder.

In other words perform a modulo operation. This operator supports object or array form. Note that the field will be converted to an integer (effectively a math floor) before the modulo operation.

Referenced in

Example

{
  "$mod": [
    2,
    0
  ]
}

More examples

{
  "$mod": {
    "divisor": 2,
    "remainder": 0
  }
}
{
  "from": "products",
  "where": {
    "price": {
      "$mod": {
        "divisor": 2,
        "remainder": 0
      }
    }
  }
}

$multiply

Availability: API v1 · API v2 (beta) — v2 form: $multiply

Multiplication operation of given items.

Format

{
  "$multiply": [Score]
}

Referenced in

Example

{
  "$multiply": [
    "price",
    2
  ]
}

$divide

Availability: API v1 · API v2 (beta) — v2 form: $divide

Division operation.

Format

{
  "$divide": object or [Score]
}

Referenced in

Example

{
  "$divide": [
    "cost",
    4
  ]
}

$pow

Availability: API v1

Exponentiation operation. First item raised to the power of the second.

Referenced in

Example

{
  "$pow": [
    "width",
    2
  ]
}

$sum

Availability: API v1 · API v2 (beta) — v2 form: $sum

Calculates sum of given items.

Format

{
  "$sum": ContextValueQuery or [Score]
}

Referenced in

Example

{
  "$sum": [
    "priceNet",
    "priceVat"
  ]
}

$subtract

Availability: API v1 · API v2 (beta) — v2 form: $subtract

Subtraction operation.

Format

{
  "$subtract": object or [Score]
}

Referenced in

Example

{
  "$subtract": [
    "price",
    2
  ]
}

Advanced operators

More advanced operators which can improve query results in certain situations.

$atomic

Availability: API v1 · API v2 (beta)

Transforms a statement into a 'black box' proposition.

This prevents Aito from analyzing the proposition and using its parts separately in the statistical reasoning.

In practice the difference between normal 'white box' expressions, and the $atomic's black box expressions is: that the atomic expressions have a smaller bias, but a higher measurement error.

Consider the following example:

{
  "tags": "pen",
  "price": { "$gte": 200 } }
}

During the statistical reasoning: Aito may recognize that pens are often sold, and that over 200€ product purchases are somewhat common. As a result, Aito might assume the over 200€ pen to be a popular product.

Now, consider the expression:

{
  "$atomic": {
    "tags": "pen",
    "price": { "$gte" : 200 }
  }
}

The results of this expression will depend of the amount of data. If there are no over 200€ pens in the data: Aito will make no assumptions of the proposition's effect. On the other hand, if you have the data: Aito will recognize correctly, that the over 200€ pens are bought extremely rarely.

Format

{
  "$atomic": Proposition
}

Referenced in

Example

{
  "$atomic": {
    "tags": "pen",
    "price": {
      "$gte": 200
    }
  }
}

More examples

{
  "from": "products",
  "where": {
    "$atomic": {
      "tags": "pen",
      "price": {
        "$gte": 200
      }
    }
  }
}

Exact

Availability: API v1 · API v2 (beta) — v2 form: $exact

Prevents featurization of the underlying proposition. Similar to $atomic, but even more precise: where $atomic keeps the proposition's parts together as one black-box statement, $exact also skips the field's analyzer, matching the raw stored value.

For example, on a Text field with an English analyzer:

{
  "query": { "$exact": "electric guitar" }
}

matches only rows where the query field contains exactly "electric guitar", treating it as a single proposition rather than decomposing it into the individual tokens ("electr", "guitar").

The value can be a plain value or a wrapped proposition:

{ "$exact": "exact phrase" }
{ "$exact": { "$is": "exact phrase" } }

Format

{
  "$exact": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "$exact": "exact phrase"
}

More examples

{
  "$exact": {
    "$is": "exact phrase"
  }
}
{
  "from": "products",
  "where": {
    "text": {
      "$exact": "exact phrase"
    }
  }
}

$context

Availability: API v1 · API v2 (beta) — v2 form: $context

Provides ability to access the fields of the table specified in "from", instead of fields of the table in "get".

Format

{
  "$context": Proposition
}

Referenced in

Example

{
  "$context": {
    "click": true
  }
}

More examples

{
  "from": "impressions",
  "where": {
    "customerEmail": "john.doe@aito.ai",
    "query": "laptop"
  },
  "get": "product",
  "orderBy": {
    "$p": {
      "$context": {
        "click": true
      }
    }
  }
}

$hit

Availability: API v1

Provides ability to access the fields of the hit.

Format

{
  "$hit": Score
}

Referenced in

Example

{
  "$hit": "price"
}

More examples

{
  "$hit": "$similarity"
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$multiply": [
      {
        "$hit": "$similarity"
      },
      {
        "$hit": "price"
      }
    ]
  }
}

$on

Availability: API v1 · API v2 (beta) — v2 form: $on

$on operator is used to define conditional propositions or hard filters.

This is useful when you have limited amount of data and the condition would help to limit the context and provide better results. This can be done by providing a list containing of two items, the first object (or "prop") is the hypothesis and the second object (or "on") is the conditional.

In Aito the where clause contains propositions which aren't hard filters. Instead, Aito will turn all the propositions into features (the user's ID, every word in a text field, etc.). There are many of these and they are not statistically independent. Aito picks a subset of these features that are the best predictors of the field that is to be predicted. So what goes into the "where" is a description of the situation you're in and Aito tells you what you should expect to find if you look in a field. But the description is not taken at face value, Aito will ignore parts of it if it doesn't help the prediction.

However, there is another way to achieve this: the "$on" proposition. It is modeled after conditional probability. It is divided into two parts, the normal "where" parts and the conditional part ("hard filters"). The "$on" parameters explained:

{
  "from": "...",
  "where": {
    "$on": [
      {
        "message": "hello, world",
        "something": true,
        // other things you put in your "where" clause
      },
      {
        // The subset of data that exactly matches these conditions
        "userId": 42,
        "day": "monday"
      }
    ]
  },
  "predict": "..."
}

The $on can also be combined with normal query. If the $on condition is too strong, you could move parts of the filtering back to the where clause:

{
  "from": "...",
  "where": {
    "$on": [
      {
        "message": "hello, world",
        "something": true,
        // other things you put in your "where" clause
      },
      {
        // The subset of data that exactly matches these conditions
        "day": "monday"
      }
    ],
    "user_id": 42
  },
  "predict": "..."
}

Referenced in

Example

{
  "$on": {
    "prop": {
      "click": true
    },
    "on": {
      "user.tags": "nyc"
    }
  }
}

More examples

{
  "$on": [
    {
      "click": true
    },
    {
      "user.tags": "nyc"
    }
  ]
}

$knn

Availability: API v1 · API v2 (beta) — v2 form: $knn

The $knn operator is an adaptation of the classic k-nearest neighbor algorithm.

Aito's $knn operator identifies k most similar rows to the conditions defined in the 'near' parameter. The similarity metric is the same metric used in the similarity query. The k nearest rows can be used in inference.

The $knn operator can be useful in situation where there is no training data. For example:

{
  "from": "impressions",
  "where": {
    "product.name": "Columbian Coffee",
    "product.tags": "high quality coffee"
  },
  "predict": "purchase"
}

The query would not yield sensible results since there's no such product existed in the current data. This can be improved by using the $knn operator:

{
  "from": "impressions",
  "where": {
    "$knn": {
      "k": 5,
      "near": {
        "product.name": "Columbian Coffee",
        "product.tags": "high quality coffee"
      }
    }
  },
  "predict": "purchase"
}

In the query above, Aito would look for 5 entries that are most similar to the given criteria in "near" and use that for inference.

Referenced in

Example

{
  "$knn": [
    4,
    {
      "tags": "laptop"
    }
  ]
}

More examples

{
  "$knn": {
    "k": 4,
    "near": {
      "tags": "laptop"
    }
  }
}

$nn

Availability: API v1 · API v2 (beta) — v2 form: $nn

The $nn operator is similar to the classic k-nearest neighbor algorithm, except that it matches a dynamic number of entries that are roughly the same as the specified proposition.

Aito's $nn operator identifies all rows that are roughly same to the conditions defined in the 'near' parameter. This group of parameters can be used in inference. This rough sameness is based on the same score used in the $sameness, and you can inspect the score of the matching values with the following query:

{
  "from": "rfps",
  "where": {
    "$nn": [{
      "question": "Does your company comply to ISO 27001?"
    }]
  },
  "orderBy": "$sameness"
}

$nn accepts also threshold parameter that can used to make matching stricter or looser like here:

{
  "from": "rfps",
  "where": {
    "$nn": [{
      "question": "Does your company comply to ISO 27001?"
    }, 0.5]
  },
  "orderBy": "$sameness"
}

The default threshold is 1.0.

An examples of using $nn in inference relates to question answering setting, where there is a desire to avoid false positive present in classic $knn or the default Bayesian inferences.

An example of using $nn for answering RFP question is following:

{
  "from": "rfps",
  "where": {
    "question": {
      "$nn": ["Does your company comply to ISO 27001?"]
    }
  },
  "predict": "answer"
}

This specific question will match similar question in the database. Still, because this question may also match questions like 'Does your comply with ISO 9001?', it makes sense to to also use the question's 'Does your comply with ISO 9001?' conditional features in inference like this:

{
  "from": "rfps",
  "where": {
    "question": {
      "$on": [
        "Does your company comply to ISO 27001?",
        {"$nn": ["Does your company comply to ISO 27001?"]}
      ],
      "$nn": ["Does your company comply to ISO 27001?"]
    }
  },
  "predict": "answer"
}

In this example, we $nn identifies a group of similar questions and uses these in the inference. At the same time $on structure allows the inference to see e.g. ISO 27001 as a separate feature inside this group. In this way, the system can focus on similar questions, while using individual features like ISO 27001 to infer the right answer.

Referenced in

Example

{
  "$nn": [
    {
      "tags": "laptop"
    }
  ]
}

More examples

{
  "$nn": {
    "near": {
      "tags": "laptop"
    }
  }
}

$numeric

Availability: API v1 · API v2 (beta) — v2 form: $numeric

Operator to check if a numeric field fuzzy matches a given number.

By default, numbers are compared exactly against one another. The $numeric proposition signifies that comparisons should be inexact and that the target is somewhere close to the specified number. The size of the region depends on the spread and density of the data.

Format

{
  "$numeric": GetValueExpression or integer or integer or number or null
}

Referenced in

Example

{
  "$numeric": 42
}

More examples

{
  "$numeric": 3.14
}

$hash

Availability: API v1 · API v2 (beta) — v2 form: $hash

$hash converts the field value into a hash integer.

The hash code can be used to split non-integer data pseudo-randomly in the evaluate query.

Format

{
  "$hash": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "$hash": {
    "$mod": [
      2,
      1
    ]
  }
}

$toString

Availability: API v1 · API v2 (beta)

$toString operator is used to convert a nummeric value to string.

This is useful when you want to use a numeric as input for an operator or a field that requires text input. For example:

{
  "description": {
    "$match": {
      "$toString": { "$get": "id" } 
    }
  }
}

Format

{
  "$toString": GetValueExpression or integer or integer or number or null or ArrayValue or $toString or boolean or string or Json
}

Example

{
  "$toString": 4
}

Scoring operators

Can be used in "orderBy" clause to sort or create an advanced scoring algorithm.

$p

Availability: API v1 · API v2 (beta) — v2 form: $p

"$p" can be used in the "orderBy" clause of the Generic query to get the most probable values. When used this way, it is similar to the Match query.

In the grocery demo dataset, running the following query would yield products with name similar to "lactose" that have the highest probabilities that it would be purchased:

{
  "from": "impressions",
  "where": {
    "product.name": {"$match": "lactose"}
  },
  "get": "purchase",
  "orderBy": "$p"
}

Similar to the Match query, running the following query would yield the most likely product based on all the fields of the linked product table:

{
  "from": "impressions",
  "where": {
    "context.user": "bob",
    "purchase": true
  },
  "get": "product",
  "orderBy": "$p"
}

Since the product field in the impressions table is linked to the products table, Aito would find all the statistical relations between what is declared inside the "where" clause and all the fields feature of a product, that is, id, name, category, price, tag. In this case, the probability score is the normalized product of the lift of each field's feature. We can investigate this by opening up the explanation adding the $why operator to the "select" clause (e.g: "select": ["$score", "$why"]):

"$why": {
  "type": "product",
  "factors": [
    {
      "type": "hitPropositionLift",
      "proposition": { "id" : 6410405093677 },
      "value": 1.9827806375460209,
      "factors": [
        {
          "type": "relatedPropositionLift",
          "proposition": { "purchase" : true },
          "value": 1.9827806375460209
        }
      ]
    },
    {
      "type": "hitPropositionLift",
      "proposition": { "$not" : { "name" : { "$has": "puikula" } } },
      "value": 1.0472308585357502,
      "factors": [
        {
          "type": "relatedPropositionLift",
          "proposition": { "purchase" : true },
          "value": 1.0472308585357502
        }
      ]
    }
    ...
  ]
}

We can see that the probability score is composed of lift of an id feature, a name feature and others.

See also $p and $lift.

Referenced in

Example

"$p"

More examples

{
  "from": "messages",
  "get": "user",
  "orderBy": "$p",
  "where": {
    "message": {
      "$match": "dog"
    }
  }
}

$f

Availability: API v1 · API v2 (beta) — v2 form: $f

"$f" can be used in the "orderBy" clause of the Generic query to get the frequency of a feature.

Referenced in

Example

"$f"

More examples

{
  "from": "impressions",
  "get": "product",
  "orderBy": "$f"
}

$lift

Availability: API v1 · API v2 (beta) — v2 form: $lift

"$lift" can be used in the "orderBy" clause of the Generic query to get the most likely values based on lifts of features with regard to other features.

In the grocery demo dataset, running the following query would yield products with name similar to "lactose" that have the highest lifts that it would be purchased:

{
  "from": "impressions",
  "where": {
    "product.name": {"$match": "lactose"}
  },
  "get": "purchase",
  "orderBy": "$lift"
}

Running the following query would yield the most likely product based on all the fields of the linked product table:

{
  "from": "impressions",
  "where": {
    "context.user": "bob",
    "purchase": true
  },
  "get": "product",
  "orderBy": "$lift"
}

Since the product field in the impressions table is linked to the products table, Aito would find all the statistical relations between what is declared inside the "where" clause and all the fields feature of a product, that is, id, name, category, price, tag. In this case, the lift score is the product of the lift of each field's feature. We can investigate this by opening up the explanation adding the $why operator to the "select" clause (e.g: "select": ["$score", "$why"]):

"$why": {
  "type": "product",
  "factors": [
    {
      "type": "hitPropositionLift",
      "proposition": { "id" : 6410405093677 },
      "value": 1.9827806375460209,
      "factors": [
        {
          "type": "relatedPropositionLift",
          "proposition": { "purchase" : true },
          "value": 1.9827806375460209
        }
      ]
    },
    {
      "type": "hitPropositionLift",
      "proposition": { "$not": { "name" : {"$has": "puikula" } } },
      "value": 1.0472308585357502,
      "factors": [
        {
          "type": "relatedPropositionLift",
          "proposition" : { "purchase" : true },
          "value": 1.0472308585357502
        }
      ]
    }
    ...
  ]
}

We can see that the lift score is composed of lift of an id feature, a name feature and others.

See also $p and $lift.

Referenced in

Example

"$lift"

More examples

{
  "from": "messages",
  "get": "user",
  "orderBy": "$lift",
  "where": {
    "message": {
      "$match": "dog"
    }
  }
}

$similarity

Availability: API v1 · API v2 (beta) — v2 form: $similarity

"$similarity" can be used in Generic query to get most similar rows based on the contents of the "where" clause.

Consider the following example. It will return all the products, that contain 'iphone' in the title. It also sorts the results by their similarity to the 'iphone' and highlight the 'iphone' term in the product title field.

{
  "from": "product",
  "where": { "title": { "$match": "iphone" } },
  "get": "message",
  "orderBy": "$similarity",
  "select": ["title", "$highlight"]
}

Referenced in

Example

"$similarity"

More examples

{
  "from": "product",
  "get": "message",
  "orderBy": "$similarity",
  "where": {
    "title": {
      "$match": "iphone"
    }
  }
}

$sameness

Availability: API v1 · API v2 (beta) — v2 form: $sameness

"$sameness" can be used in Generic query to get most roughly the same rows based on the contents of the "where" clause.

Consider the following example. It will return all the questions, that are roughly same as 'How can I order a sim card?' based on how closely they match the question.

{
  "from": "questions",
  "where": { "title": { "$nn": ["How can I order a sim card?"] } },
  "get": "message",
  "orderBy": "$sameness"
}

Referenced in

Example

"$sameness"

More examples

{
  "from": "product",
  "orderBy": "$sameness",
  "where": {
    "title": {
      "$match": "iphone"
    }
  }
}

$hit

Availability: API v1

Provides ability to access the fields of the hit.

Format

{
  "$hit": Score
}

Referenced in

Example

{
  "$hit": "price"
}

More examples

{
  "$hit": "$similarity"
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$multiply": [
      {
        "$hit": "$similarity"
      },
      {
        "$hit": "price"
      }
    ]
  }
}

$p object

Availability: API v1

Conceptually similar to the plain $p operator, but allows using a customized proposition for the probability score calculation.

This $p operator enables more options to customized the probability score calculation, especially when getting the values of linked table:

  1. Narrow down the fields that are used to calculate the probability: This is similar to the behavior of the "basedOn" clause of the Match query When calculating the probability of a linked field, aito used all the fields of the linked table (See $p for how the probability is calculated for a linked field). If you would like to narrow down how the probability is calculated, you can add the field name following the $p. For example, find the most likely product based on only the product name:
{
  "from": "impressions",
  "where": {
    "context.user": "bob",
    "purchase": true
  },
  "get": "product",
  "orderBy": {
    "$p": "name"
  }
}

You can also calculate the probability based on multiple fields by using the array format. For instance:

{
  "$p": ["category", "tag"]
}
  1. Calculate the probability based on a specific context: This is similar to the behavior of the Recommend query By combining with the $context operator, the probability score can be defined as the probability of a context. For instance, to find the products with the highest probability that the product would be purchased:
{
  "from": "impressions",
  "where": {
    "context.user": "bob"
  },
  "get": "product",
  "orderBy": {
    "$p": {"$context": {"purchase": true}}
  }
}

Format

{
  "$p": PropositionSet
}

Referenced in

Example

{
  "$p": "tags"
}

More examples

{
  "$p": [
    "tags",
    "title"
  ]
}
{
  "$p": {
    "$context": {
      "click": true
    }
  }
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$p": "tags"
  }
}

$probability

Availability: API v1

Declares the probability of the given proposition(s). This is a more configurable version of $p operation

Note the basedOn field can be used to reduce noise in recommendations. BasedOn contains the list of fields in hit table, that are used in the probability calculation. If basedOn is not defined, all fields are used, including the noisy ones.

Used in order by to sort the result by the probability in descending order.

Format

{
  "$probability": object
}

Referenced in

Example

{
  "$probability": {
    "of": "tags"
  }
}

More examples

{
  "$probability": {
    "of": [
      "tags",
      "title"
    ]
  }
}
{
  "$probability": {
    "of": {
      "$context": {
        "click": true
      }
    },
    "basedOn": [
      "title",
      "tags",
      "category"
    ]
  }
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$probability": {
      "of": "tags"
    }
  }
}

$lift object

Availability: API v1

Conceptually similar to the plain $lift operator, but allows using a customized proposition for the lift score calculation.

This $lift operator enables more options to customized the lift score calculation, especially when getting the values of linked table.

  1. Narrow down the fields that are used to calculate the lift: This is similar to the behavior of the "basedOn" clause of the Match query When calculating the lift of a linked field, aito used all the fields of the linked table (See $lift for how the lift is calculated for a linked field). If you would like to narrow down how the lift is calculated, you can add the field name following the $lift. For example, find the most likely product based on only the product name:
{
  "from": "impressions",
  "where": {
    "context.user": "bob",
    "purchase": true
  },
  "get": "product",
  "orderBy": {
    "$lift": "name"
  }
}

You can also calculate the lift based on multiple fields by using the array format. For instance:

{
  "$lift": ["category", "tag"]
}
  1. Calculate the lift based on a specific context: This is similar to the behavior of the Recommend query By combining with the $context operator, the lift score can be defined as the lift of a context. For instance, to find the products with the highest lift of getting purchased:
{
  "from": "impressions",
  "where": {
    "context.user": "bob"
  },
  "get": "product",
  "orderBy": {
    "$lift": {"$context": {"purchase": true}}
  }
}

Format

{
  "$lift": PropositionSet
}

Referenced in

Example

{
  "$lift": "tags"
}

More examples

{
  "$lift": [
    "tags",
    "title"
  ]
}
{
  "$lift": {
    "$context": {
      "click": true
    }
  }
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$lift": "tags"
  }
}

$probabilityLift

Availability: API v1

Declares the lift of the given proposition(s). This is more configurable version of $lift.

NOTE: This can be used if recommendations pick noise from irrelevant fields. Overall, using only relevant fields often makes inference both more accurate and faster.

Used in order by to sort the result by the probability in descending order.

Format

{
  "$probabilityLift": object
}

Referenced in

Example

{
  "$probabilityLift": {
    "of": "tags"
  }
}

More examples

{
  "$probabilityLift": {
    "of": [
      "tags",
      "title"
    ]
  }
}
{
  "$probabilityLift": {
    "of": {
      "$context": {
        "click": true
      }
    },
    "basedOn": [
      "title",
      "tags",
      "category"
    ]
  }
}
{
  "from": "impressions",
  "where": {
    "product.title": {
      "$match": "iphone"
    }
  },
  "get": "product",
  "orderBy": {
    "$probabilityLift": {
      "of": "tags"
    }
  }
}

$mean

Availability: API v1

The mean of given value in context

Example 1:

    {
      "$mean": {
        "$context": "score"
      }
    }
                            

Format

{
  "$mean": ContextValueQuery
}

Referenced in

Example

{
  "$mean": {
    "$context": "score"
  }
}

$freqP

Availability: API v1

An empirical frequency based probability estimate

$freqP allows you to specify two fields, called f (success) and n (trials) and an additional field called p (prior probability).

$freqP will calculate probability estimate for each row based on the f (success), n (trials) and p (prior probability) fields. Priori probability is the probability of success before any data is observed and 0.5 by default.

$freqP comes also with variance information, which means that it can be used together with $decision operation to solve the multi-armed bandit problem.

Format

{
  "$freqP": object
}

Referenced in

Example

{
  "$freqP": {
    "f": "clickCount",
    "n": "impressionCount",
    "p": 0.5
  }
}

$decision

Availability: API v1

$decision-feature exist to solve the multi-armed bandit problem, where we have:

  1. Decision options with uncertainty about the reward probabilities
  2. And need to gather more data from the options to better estimate reward probabilities

This problem exist classically in advertisement, where there is uncertainity of the click-through rate of the ads. In such case, one needs to find a trade-off between exploring new ads and exploiting the best ads.

$decisions operation returns a 'decision' score, which can be used to randomly order options and select the first one(s). It implements a Bayesian solution, where the decision score is sampled from a normal distribution, that uses the mean and standard error of the given score.

NOTE: that $decision only works with scores having an inherent variance information. This variance is present right now only with numerical estimates calculated with $sum and $freqP. $decision is not yet supported for e.g. $p or basic probability calculation.

Format

{
  "$decision": object
}

Referenced in

Example

{
  "$decision": {
    "score": {
      "$mean": {
        "$context": "clickThroughRate"
      }
    },
    "seed": 0
  }
}

$similarity object

Availability: API v1 · API v2 (beta) — v2 form: $similarity

Conceptually similar to the plain $similarity operator, but allows using a customized proposition for the similarity score calculation.

The plain $similarity operator calculates the similarity score based on the "where" clause contents, whereas this $similarity operator calculates the similarity score based on the given proposition.

These Generic Queries would yield the same results:

{
  "from": "products",
  "where": {
    "name": {"$match": "coffee"}
  },
  "orderBy": "$similarity"
}
{
  "from": "products",
  "orderBy": {
    "$similarity": {
      "name": "coffee"
    }
  }
}

This $similarity operation is useful for customizing scoring as the example below. Please refer to GenericQuery query with custom scoring example.

{
  "from": "impressions",
  "where": {
    "context.user": "veronica"
  },
  "get": "product",
  "orderBy": {
    "$multiply": [
      {
        "$p": {
          "$context": {
            "purchase": true
          }
        }
      },
      {
        "$similarity": {
          "name": "coffee"
        }
      }
    ]
  }
}

Format

{
  "$similarity": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "$similarity": {
    "title": "apple iphone",
    "tags": "premium ios phone"
  }
}

More examples

{
  "from": "products",
  "orderBy": {
    "$similarity": {
      "title": "apple iphone",
      "tags": "premium ios phone"
    }
  }
}

$sameness object

Availability: API v1 · API v2 (beta) — v2 form: $sameness

This operator provides a score, which reflect whether the return entry is roughly the same as the given proposition / data.

E.g. if you have a phrase "How to order a sim card?" it should be judged roughly the same as "Ho can I order a sim card?". The values above 1 are considered to be roughly same and values under 1 are considered to be roughly distinct.

$sameness works in similar way to $similarity, except that it does more strict matching. E.g. query "sim card" provides above 1 similarity score with "How can I order sim card?", but it provides significantly under 1 sameness score. $sameness works better in situations, where a more restrictive is scoring is needed to avoid false matches. An example of this is e.g. question answering situation where, where one needs to match questions more strictly in order to avoid false positivess

Format

{
  "$sameness": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "$sameness": {
    "title": "apple iphone",
    "tags": "premium ios phone"
  }
}

More examples

{
  "from": "products",
  "orderBy": {
    "$sameness": {
      "title": "apple iphone",
      "tags": "premium ios phone"
    }
  }
}

$analogy object

Availability: API v1

This operator provides a score, which reflect whether the return entry is analogious with the given value in respect to some other values.

E.g. if you have a query word 'cheap' it should have a high $analogy score with words like affordable and inexpensive in respect to correct query result.

E.g. if you have a text "Netflix has great series" it should have a high $analogy score with in respect to a text like 'There are good movies' in respect to sentiment or feedback category.

Format

{
  "$analogy": object
}

Referenced in

Example

{
  "$analogy": {
    "with": "veronica",
    "basedOn": "purchases"
  }
}

More examples

{
  "from": "products",
  "get": "title",
  "orderBy": {
    "$analogy": {
      "with": "ideapad",
      "basedOn": "tags"
    }
  }
}

$normalize

Availability: API v1

$normalize operator can be used in the "orderBy" clause of the Generic query to make a score to sum to 1. For example, you can normalize the $lift or the $lift object to 1:

{
  "from": "impressions",
  "where": {
    "product.name": {"$match": "lactose"}
  },
  "get": "purchase",
  "orderBy": {
    "$normalize": "$lift"
  }
}

or

{
	"from": "impressions",
	"where": {
		"context.user": "bob",
		"purchase": true
	},
	"get": "product",
	"orderBy": {
		"$normalize": {
      "$lift": { "$context": { "click": "true" } }
    }
	}
}

Format

{
  "$normalize": Score
}

Referenced in

Example

{
  "$normalize": "$lift"
}

More examples

{
  "$normalize": {
    "$lift": "name"
  }
}

$impact

Availability: API v1

Impact of the scored valued (like product) to a value in the context (like star rating) relative to base. If base is not given, the value average is used instead.

Format

{
  "$impact": object
}

Referenced in

Example

{
  "$impact": {
    "value": {
      "$context": "score"
    },
    "base": 2.5
  }
}

More examples

{
  "from": "projects",
  "get": "customer.industry",
  "orderBy": {
    "$impact": {
      "value": {
        "$context": "profit"
      }
    }
  }
}

$f (context)

Availability: API v1

The frequency / count of the given proposition in context.

Format

{
  "$f": ContextPropositionQuery
}

Referenced in

Example

{
  "$f": {
    "$context": {
      "click": false
    }
  }
}

More examples

{
  "from": "impressions",
  "get": "product",
  "orderBy": {
    "$f": {
      "$context": {
        "$click": true
      }
    }
  }
}

Aggregate operators

Can be used in aggregate operation.

$mean

Availability: API v1 · API v2 (beta) — v2 form: $mean

Mean or average. Can be used to calculate the average of a field. Similar to SQL AVERAGE operation.

Format

{
  "$mean": Score
}

Referenced in

Example

{
  "$mean": "ctr"
}

More examples

{
  "$mean": {
    "$freqP": {
      "f": "clicks",
      "n": "impressions"
    }
  }
}

$sum

Availability: API v1 · API v2 (beta) — v2 form: $sum

Sum. Can be used to calculate the sum of the field.

Format

{
  "$sum": Score
}

Referenced in

Example

{
  "$sum": "visits"
}

More examples

{
  "$sum": "purchase"
}

$f (aggregate)

Availability: API v1

Count the frequency of cases the proposition / condition is true

Format

{
  "$f": Proposition
}

Referenced in

Example

{
  "$f": {
    "click": false
  }
}

More examples

{
  "$f": {
    "price": {
      "$gt": 100
    }
  }
}

NamedAggregateProjection

Availability: API v1

Allows one to name the aggregate projection results

Referenced in

Example

{
  "aggregate": {
    "clicks": {
      "$f": {
        "click": true
      }
    },
    "ctr": {
      "$mean": "click"
    },
    "impressions": "$f"
  },
  "from": "impressions",
  "where": {
    "product.name": "MyProduct"
  }
}

More examples

{
  "failureCount": {
    "$f": {
      "success": false
    }
  }
}

Projection operators

Can be used in "select" clause as operators.

$index (projection)

Availability: API v1

$index selects the insertion index of a row. It can be used together with $mod to select parts of a table. It's useful for example in Evaluate query for selecting training or test data.

Referenced in

Example

"$index"

$why (object)

Availability: API v1 · API v2 (beta) — v2 form: $why

Configurable explanations. Allows providing explanation specific highlights and matching.

Note: that why will contain highlights / matches also for the where clause.

Format

{
  "$why": object
}

Referenced in

Example

{
  "$why": {
    "highlight": {
      "posPreTag": "<b>",
      "posPostTag": "</b>",
      "negPreTag": "<em>",
      "negPostTag": "</em>",
      "encoder": "html",
      "posThreshold": 1.1,
      "negThreshold": 0.9
    },
    "matches": {}
  }
}

$highlight

Availability: API v1 · API v2 (beta) — v2 form: $highlight

Sometimes, there is a need to highlight fields or individual fields' words in the examined hit. This can happen e.g. if the user is searching for specific term. Highlight can also be used in inference situations. E.g. when providing personalized search results, if the user has lactose-intolerance, it can be useful to highlight both 'lactose-free' as a positive factor and 'lactose' as a negative one.

The $highlight will provide for hit each field with HTML escaping and highlighting of positive and negative details.

  {
    "from" : "impressions",
    "where" : {
      "context.query" : "bread"
    },
    "recommend" : "product",
    "goal"      : {"purchase": true},
    "select"    : ["$p", "name", "$highlight"],
    "limit"     : 1
  }

This query produces following result containing a $highlight field:

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.5967894477818738,
      "name": "VAASAN Ruispalat 660g 12 pcs fullcorn rye bread",
      "$highlight": [
        {
          "score": 2.5780035230413474,
          "field": "name",
          "highlight": "VAASAN Ruispalat 660g 12 pcs fullcorn rye <font color=\"green\">bread</font>"
        },
        {
          "score": 2.3703213948674122,
          "field": "tags",
          "highlight": "<font color=\"green\">gluten</font> bread"
        },
        {
          "score": 4.9484160228241825,
          "field": "$context.context.query",
          "highlight": "<font color=\"green\">bread</font>"
        }
      ]
    }
  ]
}

The $highlight fields contains a list of higlights. Eech highlight specifies highlights relative importance in the score field, the field that was relevant for the hit and the field content highlighted and html encoded. Note that also the 'where' clause content is highlighted under the $context. prefix.

Referenced in

Example

"$highlight"

$highlight (object)

Availability: API v1 · API v2 (beta) — v2 form: $highlight

Parametric highlight makes it possible to highlight the most important parts of the query that contributed to the score in more configurable way. This is useful for debugging and understanding the scoring process.

The highlight is returned as a list of strings, where each string represents a part of the query that contributed to the score. The strings are ordered by importance, with the most important part first.

The highlight is only returned if the query contains at least one term that contributed to the score. If the query contains no terms that contributed to the score, the highlight is not returned.

NOTE: That highlight also highlights the fields in 'where' clause.

Parametric highlight allows user to configure positive highlight and negative highlight html tags. One can also configure the highlight sensitivity, e.g. that how positive or negative the score has to be to trigger highlight. Highlighted fields are HTML encoded by default, but this can be also disabled via parameter.

Format

{
  "$highlight": object
}

Referenced in

Example

{
  "$highlight": {
    "posPreTag": "<b>",
    "posPostTag": "</b>",
    "negPreTag": "<em>",
    "negPostTag": "</em>",
    "encoder": "html"
  }
}

$matches

Availability: API v1 · API v2 (beta) — v2 form: $matches

Sometimes, there is a need to highlight fields or individual fields' words in the examined hit. This can happen e.g. if the user is searching for specific term. Highlight can also be used in inference situations. E.g. when providing personalized search results, if the user has lactose-intolerance, it can be useful to highlight both 'lactose-free' as a positive factor and 'lactose' as a negative one.

The $matches will provide for hit each field information about how the field is related to the hit score. It's worth emphasizing that the $matches is based on the hit score. This means that the matches will contain only the features that have contributed to the hit score. So the score is the probability, the $matches will contain items, that contributed to the probability. If the score is based on similarity, the $matches will contain the features specified inside the similarity query. This means that e.g. $match operations in where clause will not be included in the $matches.

Consider the following recommend query:

  {
    "from" : "impressions",
    "where" : {
      "context.user": "larry"
    },
    "recommend" : "product",
    "goal"      : {"purchase": true},
    "select"    : ["$score", "name", "$matches"],
    "limit"     : 1
  }

This query produces following result containing a $matches field:

{
    "offset" : 0,
    "total" : 42,
    "hits" : [ {
      "$score" : 0.1346800331844607,
      "name" : "Vaasan Ruispalat thin sliced rye bread 6pcs/195g",
      "$matches" : {
        "name" : [ {
          "begin" : 33,
          "end" : 38,
          "feature" : "bread",
          "text" : "bread",
          "why" : {
            "type" : "product",
            "factors" : [ {
              "type" : "hitPropositionLift",
              "proposition" : {
                "name" : {
                  "$has" : "bread"
                }
              },
              "value" : 2.658334404390319,
              "factors" : [ {
                "type" : "relatedPropositionLift",
                "proposition" : {
                  "context.user" : {
                    "$has" : "larry"
                  }
                },
                "value" : 2.658334404390319
              } ]
            } ]
          },
          "score" : 2.658334404390319
        } ],
        "tags" : [ {
          "begin" : 0,
          "end" : 6,
          "feature" : "gluten",
          "text" : "gluten",
          "why" : {
            "type" : "product",
            "factors" : [ {
              "type" : "hitPropositionLift",
              "proposition" : {
                "tags" : {
                  "$has" : "gluten"
                }
              },
              "value" : 2.184491633564294,
              "factors" : [ {
                "type" : "relatedPropositionLift",
                "proposition" : {
                  "context.user" : {
                    "$has" : "larry"
                  }
                },
                "value" : 2.184491633564294
              } ]
            } ]
          },
          "score" : 2.184491633564294
        } ]
      }
    } ]
  }

The $matches contains separate match list for 'name' and 'tags' fields. Both fields have one match. 'Name' contains a match 'bread' as larry seems to be purchasing bread 2.67 times more often than average user. Both matches contain the begin and end positions, that identify the location of the match in the field's text. These, alongside the text field,that contains the matching original text, can be used to highlight or bold the matching statement in UI. The $why field contains the explanation for the match, and it traces the score batch to the user variable.

Feature field contains the matched feature, and it can be used inside $has proposition to find other content with the same feature.

Referenced in

Example

"$matches"

$matches (object)

Availability: API v1 · API v2 (beta) — v2 form: $matches

A version of $matches, that accepts parameters and can could be configured, except that it doesn't yet have any configuration parameters.

NOTE: That matches will also match the fields in the 'where' clause.

Format

{
  "$matches": object
}

Referenced in

Example

{
  "$matches": {}
}

NamedProjection

Availability: API v1

Named projection makes it possible to name the projected values.

This is useful for e.g. naming different averages with more descriptive names as in the following example:

{
  "ctr": {"$mean": { "$context": "click" } },
  "meanScore": {"$mean": { "$context": "score" } }
}

Referenced in

Example

{
  "from": "impressions",
  "get": "product",
  "select": {
    "clicks": {
      "$f": {
        "$context": {
          "click": true
        }
      }
    },
    "ctr": {
      "$mean": {
        "$context": "click"
      }
    },
    "impressions": "$f",
    "product": "name"
  }
}

More examples

{
  "failures": {
    "$f": {
      "$context": {
        "success": false
      }
    }
  }
}
{
  "id": "id",
  "mean": {
    "$mean": {
      "$context": "product.price"
    }
  }
}
{
  "$value": "$value",
  "field": "field",
  "id": "id"
}

Built-in attributes

Can be used in "select" clause as fields.

$index

Availability: API v1

$index is a built-in variable which indicates the insertion index of a row. It can be used together with $mod to select parts of a table. It's useful for example in Evaluate query for selecting training or test data.

Referenced in

Example

"$index"

$sort

Availability: API v1

$sort is a built-in field that can be used to access the sort value used in the orderBy-clause.

Referenced in

Example

"$sort"

$score

Availability: API v1 · API v2 (beta) — v2 form: $score

$score is a built-in field that can be used to access the sort value used in the orderBy-clause, when the sort-value is a numeric score like a probability.

Referenced in

Example

"$score"

$p

Availability: API v1 · API v2 (beta) — v2 form: $p

$p is a built-in field that can be used to access the value used by orderBy-clause, when the sort-value is a probability. See $p for more information.

Referenced in

Example

"$p"

$why

Availability: API v1 · API v2 (beta) — v2 form: $why

When selecting $why, Aito opens up why a certain result was predicted. Explanation contains 4 different factors, which are explained below.

The factors are for an estimate of form:

<InlineMath math="p(x_i | A, B, C)" />

"baseP"

The base probability.

<InlineMath math="p(X)" />

"normalizer"

Aito has two different normalizes, that are

  • exclusiveness normalizer
  • trueFalseExclusiveness normalizer

These normalizes are often grouped into a single 'product' component.

{
  "type" : "product",
  "factors" : [ {
    "type" : "normalizer",
    "name" : "exclusiveness",
    "value" : 1.0119918068684681
  }, {
    "type" : "normalizer",
    "name" : "trueFalseExclusiveness",
    "value" : 1.09917613448721
  } ]
}

The exclusiveness normalizer is only used, when exclusiveness is on. In this case, it is assumed that only one feature can be true at the same time, and that one feature will be true. In practice, exclusiveness enforces the probabilities of alternative features to sum to 1.0.

The normalizer is of form:

<InlineMath math="\\dfrac{1}{sum((p(X_0) + p(X_1) + ...))}" />

Aito makes a probability estimation for both X and ¬X on the background and uses the trueFalseExclusiveness normalizer to assert that the probabilities P(X) and P(¬X) sum to 1.0.

The normalizer is of form:

<InlineMath math="\\dfrac{1}{p(X) + p(\\neg X)}" />

"relatedVariableLift"

Probability lifts. For example: the lift may say a product is clicked with 2.3x likelihood (or 130% higher likelihood), when it has 5 stars.

A probability lift is of form:

<InlineMath math="\\dfrac{p(A | X)}{p(A)}" />

"calibration"

Aito calibrates the final probability so that its confidence reflects the amount of statistical evidence behind the prediction. Whenever the displayed $p differs from the raw product of the factors above, the difference is shown as an explicit calibration factor, so the $why breakdown always multiplies out to the displayed $p.

{
  "type" : "calibration",
  "name" : "support-tempering(auto)",
  "value" : 0.61
}

Two calibrations can appear (also combined into one factor when both are active):

  • support-tempering(auto) — on by default. Each prediction's evidence is tempered by its effective statistical support: predictions backed by many distinct training examples pass through essentially unchanged (value ≈ 1.0), while predictions whose evidence rests on few or heavily overlapping examples are softened towards the prior. Deterministic lookups and $knn/$nn style matches are recognised as regular, well-supported evidence and are not softened. Opt out with aito.neffTemper.enabled=false (see the deployment configuration reference).
  • temperature(τ=…) — a fitted global temperature from query-time calibration (config.calibrate), applied on top of support-tempering and fitting only the residual mis-calibration.

Referenced in

Example

"$why"

$value

Availability: API v1 · API v2 (beta) — v2 form: $value

$value is a built-in field which contains the value of the returned object. $value can be used to access the field value referred in the predict, match, recommend and get-clauses, when the returned item is either a field value or a field feature/proposition. $value is intended to replace the 'feature' field in the long term.

The $value field has been added to contain the information in the ‘feature’ so that for query:

  {
    "from" : "products",
    "where" : {
      "title" : "apple iphone"
    },
    "predict": "tags",
    "select" : ["$p", "$value"],
    "limit":3
  }

The result will be the following:

  {
    "offset" : 0,
    "total" : 10,
    "hits" : [ {
      "$p" : 0.3656914544001758,
      "$value" : "premium"
    }, {
      "$p" : 0.1546922568903658,
      "$value" : "cover"
    }, {
      "$p" : 0.09493670104339776,
      "$value" : "macosx"
    } ]
  }

Value works similarly, when predicting the field value, using the generic query.

  {
    "from" : "products",
    "where" : {
      "title" : "apple iphone"
    },
    "get": "tags",
    "orderBy" : "$p",
    "select" : ["$p", "$value"],
    "limit":3
  }

Or when when predicting the field features with the generic query:

  {
    "from" : "products",
    "where" : {
      "title" : "apple iphone"
    },
    "get": "tags.$feature",
    "orderBy" : "$p",
    "select" : ["$p", "$value"],
    "limit":3
  }

Referenced in

Example

"$value"

$proposition

Availability: API v1

$proposition is a built-in field which contains the proposition object of the returned feature. The returned proposition is compatible with the proposition format and it can be used as such in the where clause.

Consider the following query:

  {
    "from": "products",
    "where": {
      "title": "Apple"
    },
    "predict": {
      "$on": [
        { "$exists": "tags" },
        { "$and": [
          { "tags": { "$match": "phone" } },
          { "$not": { "tags": { "$match": "laptop" } } }
        ] }
      ]
    },
    "select": ["$p", "$value", "$proposition"],
    "limit": 1
  }

This provides the following results:

  {
    "offset" : 0,
    "total" : 10,
    "hits" : [ {
      "$p" : 0.22622976807854914,
      "$value" : "phone",
      "$proposition" : {
        "$on" : [ {
          "tags" : {
            "$has" : "phone"
          }
        }, {
          "$and" : [ {
            "tags" : {
              "$has" : "phone"
            }
          }, {
            "$not" : {
              "tags" : {
                "$has" : "laptop"
              }
            }
          } ]
        } ]
      }
    } ]
  }

Referenced in

Example

"$proposition"

Explanation objects

Explanation object when using the "$why" operator.

SumExplanation

Availability: API v1

Explain how a summation was calculated.

The SumExplanation most commonly appears when opening up the explanation (e.g: using the $why operator) of a score calculated using the $sum operator.

Format

{
  "type": string,
  "terms": [ScoreExplanation]
}

Referenced in

Example

{
  "terms": [
    {
      "field": "id",
      "type": "field",
      "value": 4
    },
    {
      "field": "price",
      "type": "field",
      "value": 1500
    }
  ],
  "type": "sum"
}

SubtractionExplanation

Availability: API v1

This explanation object explains how a substraction result was calculated. It occurs in $why results, if $subtract operation is used.

Format

{
  "type": string,
  "minuend": ScoreExplanation,
  "subtrahend": ScoreExplanation
}

Referenced in

Example

{
  "minuend": {
    "field": "price",
    "type": "field",
    "value": 119.5
  },
  "subtrahend": {
    "field": "cost",
    "type": "field",
    "value": 100.5
  },
  "type": "subtraction"
}

ProductExplanation

Availability: API v1

This explanation object explains how a product score was calculated. It occurs in $why results, if $multiply operation is used.

The ProductExplanation most commonly appears when opening up the explanation (e.g: using the $why operator) of:

  1. Aggregated score by product. For example, in a Match query:
{
  "from": "impressions",
  "where": {
    "context.user": "larry"
  },
  "match": "product",
  "select": ["$score", "name", "$why"]
}

The final score is a product of multiple score components:

{
  "type": "product",
  "factors": [
    {
      "type": "hitPropositionLift",
      "proposition": { "id" : 6410405216120 },
      "value": 599.5491890842981,
      "factors": [
        {
          "type": "baseLift",
          "value": 265.0
        },
        {
          "type": "relatedPropositionLift",
          "proposition": { "context.user" : "larry" },
          "value": 2.2624497701294266
        }
      ]
    },
    ...
  ]
}
  1. A score calculated using the $multiply operator.

Format

{
  "type": string,
  "factors": [ScoreExplanation]
}

Referenced in

Example

{
  "factors": [
    {
      "factors": [
        {
          "type": "baseLift",
          "value": 31
        }
      ],
      "proposition": {
        "id": 3
      },
      "type": "hitPropositionLift",
      "value": 31
    },
    {
      "field": "price",
      "type": "field",
      "value": 1500
    }
  ],
  "type": "product"
}

BaseLiftExplanation

Availability: API v1

Conceptually similar to BaseProbabilityExplanation but show the prior lift instead of prior probability.

See more Probability vs. Lift

Format

{
  "type": string,
  "value": number
}

Referenced in

Example

{
  "type": "baseLift",
  "value": 31
}

DivisionExplanation

Availability: API v1

This explanation object explains how a division result was calculated. It occurs in $why results, if $divide operation is used.

Format

{
  "type": string,
  "dividend": ScoreExplanation,
  "divisor": ScoreExplanation
}

Referenced in

Example

{
  "dividend": {
    "field": "return",
    "type": "field",
    "value": 400000
  },
  "divisor": {
    "field": "investment",
    "type": "field",
    "value": 250000
  },
  "type": "division"
}

BaseProbabilityExplanation

Availability: API v1

Explain the initial weight of a feature. It can be understand as the prior probability <InlineMath math="p(X)" /> of a feature.

Let's take a look at an example of a Predict query:

{
  "from": "products",
  "where": {
    "name": "Columbian coffee"
  },
  "predict": "tags",
  "select": ["$p", "feature", "$why"]
}

When opening up the explanation with "$why" operator, a tag's feature "coffee" has a BaseProbabilityExplanation:

{
  "type": "baseP",
  "value": 0.16
}

This explanation tells that Aito gives the feature "coffee" a prior probability of 0.16.

Format

{
  "type": string,
  "value": number,
  "proposition": PropositionExplanation
}

Referenced in

Example

{
  "proposition": {
    "click": true
  },
  "type": "baseP",
  "value": 0.5
}

Availability: API v1

Explain how a related variable's lift was calculated.

A related variable (feature) most commonly appears when doing inference with some conditions. The RelatedVariableLiftExplanation explains how a variable of the conditions affecting the lift of a hit's variable.

Let's take a look at an example of Match query:

{
  "from": "impressions",
  "where": {
    "context.user": "larry"
  },
  "match": "product",
  "select": ["$score", "name", "$why"]
}

When opening up the explanation with "$why" operator, the first hit has an explanation as follows:

{
  "type": "hitVariableLift",
  "variable": "id:6410405216120",
  "value": 599.5491890842981,
  "factors": [
    {
      "type": "baseLift",
      "value": 265.0
    },
    {
      "type": "relatedVariableLift",
      "variable": "context.user:larry",
      "value": 2.2624497701294266
    }
  ]
}

This explains that the feature "context.user:larry" extracted from the conditions "where": { "context.user": "larry" } enhances the likelihood that the product having an id of 6410405216120 with a lift of 2.2624497701294266.

Format

{
  "type": string,
  "proposition": PropositionExplanation,
  "value": number
}

Referenced in

Availability: API v1

Explain how a propositions's lift was calculated.

HitLinkPropositionLiftExplanation explains the impact of the value that links to table containing the returned hits.

Let's consider an example, where there is an impression table that has a numeric field 'product' that links to the product table. In such a case the HitLinkPropositionLift would explain the significance of the field 'product' in the impression table. E.g., if the product link's value is 4, the HitLinkPropositionLiftExplanation will explain the effect of the proposition { "product" : 4 }. If the value is 2.0, it means that the 4 product is estimated to be twice as probable just based on the statistics of the linking column.

Format

{
  "type": string,
  "proposition": PropositionExplanation,
  "value": number
}

Referenced in

Example

{
  "proposition": {
    "product": 5
  },
  "type": "hitLinkPropositionLift",
  "value": 2.32
}

DecoratedScoreExplanation

Availability: API v1

This format is essentially a normal score explanation, but it can contain additional $matches and $highlight fields. It is returned when ParametricWhy is used.

Referenced in

HitPropositionLiftExplanation

Availability: API v1

Explain how a propositions's lift was calculated.

A hit score was calculated by aggregating the score of its propositions (features). The HitPropositionLiftExplanation explains how different proposition was calculated.

A HitPropositionLift can be:

  1. A similarity score A hit's field can contain a word that match the stem of the given similarity condition. That word would have a HitPropositionLift that is a similarity score. Let's take a look at an example of Similarity query:
{
  "from": "products",
  "similarity": {
    "name": "Columbian coffee",
    "tags": "expansive coffee"
  },
  "select": ["$score", "name", "tags", "$why"]
}

When opening up the explanation with "$why" operator, we can see that a hit with name "Juhla Mokka coffee 500g sj" containing the word coffee has a HitPropositionLiftExplanation as follows:

{
  "type": "hitPropositionLift",
  "proposition": "name:coffe",
  "value": 2.1726635013471625,
  "factors": [
    {
      "type": "exponent",
      "value": 2.1726635013471625,
      "base": {
        "type": "idf",
        "value": 2.1726635013471625
      },
      "power": {
        "type": "tf",
        "value": 1.0
      }
    }
  ]
}
  1. An aggregated score of BaseLift and RelatedPropositionLift

Let's take a look at an example of Match query:

{
  "from": "impressions",
  "where": {
    "context.user": "larry"
  },
  "match": "product",
  "select": ["$score", "name", "$why"]
}

When opening up the explanation with "$why" operator, the first hit has a HitPropositionLiftExplanation as follows:

{
  "type": "hitPropositionLift",
  "proposition": { "id" : { "$has" : 6410405216120 } },
  "value": 599.5491890842981,
  "factors": [
    {
      "type": "baseLift",
      "value": 265.0
    },
    {
      "type": "relatedPropositionLift",
      "proposition": { "context.user": { "$has" : "larry" } },
      "value": 2.2624497701294266
    }
  ]
}

This explains that the initial lift of the feature "id:6410405216120" is 265 and when the user is Larray, the relatedPropositionLift is 2.2624497701294266. Hence the aggregated lift is <InlineMath math="265 * 2.2624497701294266 = 599.5491890842981" />

Format

{
  "type": string,
  "proposition": PropositionExplanation,
  "value": number,
  "factors": [ScoreExplanation]
}

Referenced in

Example

{
  "factors": [
    {
      "type": "baseLift",
      "value": 31
    }
  ],
  "proposition": {
    "field": 4
  },
  "type": "hitPropositionLift",
  "value": 31
}

ConstantExplanation

Availability: API v1

Default value explanation describes a constant value, typically given by the user.

Format

{
  "type": string,
  "value": number
}

Referenced in

DefaultValueExplanation

Availability: API v1

Default value explanation describes the default score for some operation.

For example TF-IDF scoring assigns default lift of 1.0 for all rows without matching terms.

Format

{
  "type": string,
  "value": number
}

Referenced in

Example

{
  "type": "default",
  "value": 1
}

NamedExplanation

Availability: API v1

Explain how a special named score was calculated.

The NamedExplanation appears in two places:

  • when calculating a score with exclusiveness, it explains the normalizer that enforces the probabilities of a feature to have sum of 1.0.
  • when the displayed probability has been calibrated, it explains the calibration factor — support-tempering(auto) (on by default; confidence tempered by the effective statistical support of the evidence) and/or temperature(τ=…) (a fitted query-time calibration). See the $why documentation for details.

Format

{
  "type": string,
  "name": string,
  "value": number
}

Referenced in

Example

{
  "name": "exclusiveness",
  "type": "normalizer",
  "value": 0.2982788431762749
}

PredictExplanation

Availability: API v1

Explain how a probability was calculated.

The PredictExplanation most commonly appears when opening up the explanation (e.g: using the $why operator) of a Predict query. Let's take a look at an example of Predict query:

  {
    "from": "products",
    "where": {
      "name": "Columbian coffee"
    },
    "predict": "tags",
    "select": ["$p", "feature", "$why"],
    "limit": 22
  }

The first hit has an explanation of"

{
  "type": "product",
  "factors": [
    {
      "type": "baseP",
      "value": 0.16
    },
    {
      "type" : "product",
      "factors" : [ 
        {
          "type" : "normalizer",
          "name" : "exclusiveness",
          "value" : 1.0119918068684681
        }, 
        {
          "type" : "normalizer",
          "name" : "trueFalseExclusiveness",
          "value" : 1.09917613448721
        } 
      ]
    },
    {
      "type": "relatedVariableLift",
      "variable": "name:coffe",
      "value": 8.45603245079726
    }
  ]
}

Format

{
  "type": string,
  "factors": [ScoreExplanation]
}

Referenced in

Example

{
  "factors": [
    {
      "type": "baseP",
      "value": 0.8048780487804879
    },
    {
      "name": "exclusiveness",
      "type": "normalizer",
      "value": 0.04604801347746731
    }
  ],
  "type": "product"
}

ExponentExplanation

Availability: API v1

Explain how an exponent score was calculated.

The ExponentExplanation most commonly appears when opening up the explanation (e.g: using the $why operator) of an exponent score such as:

  1. The tf-idf score to calculate the similarity in the Similarity query.
  2. The score of the $pow operator.

Format

{
  "type": string,
  "value": number,
  "base": ScoreExplanation,
  "power": ScoreExplanation
}

Referenced in

Example

{
  "base": {
    "type": "idf",
    "value": 1.7551720221592049
  },
  "power": {
    "type": "tf",
    "value": 1
  },
  "type": "exponent",
  "value": 1.7551720221592049
}

TermFrequencyExplanation

Availability: API v1

Explain the term frequency score.

The term frequency score is one component of the term frequency-inverse document frequency score which is used in Aito's similarity metrics.

Format

{
  "type": string,
  "value": number
}

Referenced in

Example

{
  "type": "tf",
  "value": 1
}

InverseDocumentFrequencyExplanation

Availability: API v1

Explain the inverse document frequency score.

The inverse document frequency score is one component of the term frequency-inverse document frequency score which is used in Aito's similarity metrics.

Format

{
  "type": string,
  "value": number
}

Referenced in

Example

{
  "type": "idf",
  "value": 1.7551720221592049
}

FieldExplanation

Availability: API v1

Explain how a field score was calculated.

The field explanation most commonly appears when opening up the explanation (e.g: using the $why operator) of a score that was calculated using:

  1. A field value
{
  "from" : "impressions",
  "where" : {
    "product.name":{"$match": "coffee"}
  },
  "get":"product",
  "orderBy" : {
    "$multiply": ["$p", "price"]
  },
  "select": ["$score", "$why"]
}

The explanations would contains the value of the "price" field that was use in the $multiply operator.

{
  "type": "field",
  "field": "price",
  "value": 3.95
}
  1. A field feature (e.g: $f operator for frequency):
{
  "from" : "impressions",
  "where" : {
    "product.name":{"$match": "coffee"}
  },
  "get":"product",
  "orderBy" : "$f",
  "select": ["$score", "$why"]
}

The explanation would contains the frequency of the feature.

{
  "type": "field",
  "field": "$f",
  "value": 152.0
}

Format

{
  "type": string,
  "field": string,
  "value": number
}

Referenced in

Example

{
  "field": "price",
  "type": "field",
  "value": 1500
}

Explanation proposition objects

Explanation proposition object when using the "$why" or "relate" operator.

FieldPropositionExplanation

Availability: API v1

FieldPropositionExpanation expresses a statement about a document field

For example the expression

{
  "tags": { "$has" : "laptop" }
}

states, that the tags field contains the "laptop" feature

Format

{
  "fieldName": PropositionExplanation
}

HasExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$has'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$has": IntArray or LongArray or DecimalArray or StringArray or BooleanArray or object or object or object or object or object or integer or integer or number or boolean or null or string or object
}

AndExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$and'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$and": [PropositionExplanation]
}

OrExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$or'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$or": [PropositionExplanation]
}

OnExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$on'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$on": [PropositionExplanation]
}

NotExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$not'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$not": PropositionExplanation
}

StartsWithExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$startsWith'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$startsWith": string
}

GtExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$gt'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$gt": IntArray or LongArray or DecimalArray or StringArray or BooleanArray or object or object or object or object or object or integer or integer or number or boolean or null or string or object
}

GteExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$gte'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$gte": IntArray or LongArray or DecimalArray or StringArray or BooleanArray or object or object or object or object or object or integer or integer or number or boolean or null or string or object
}

LtExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$lt'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$lt": IntArray or LongArray or DecimalArray or StringArray or BooleanArray or object or object or object or object or object or integer or integer or number or boolean or null or string or object
}

LteExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$lte'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$lte": IntArray or LongArray or DecimalArray or StringArray or BooleanArray or object or object or object or object or object or integer or integer or number or boolean or null or string or object
}

DefinedExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$defined'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$defined": boolean
}

NumericExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$numeric'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$numeric": number
}

KnnExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$knn'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$knn": object
}

NnExplanation

Availability: API v1

This format is used in the $why and relate explanations for the '$nn'-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Format

{
  "$nn": object
}

IsPropositionExplanation

Availability: API v1

This format is used in the $why and relate explanations for the is-proposition. Explanations of this format follow the normal proposition syntax and it can be reused in the where-clause.

Other types

All other API types.

ColumnName

Availability: API v1

Name of a column in a table. Links are supported.

Referenced in

Example

"id"

More examples

"age"
"product.id"

EvaluateGenericQuery

Availability: API v1

A Generic query to be evaluated in the Evaluate query

Format

{
  "from": From,
  "where": Proposition,
  "get": Get,
  "orderBy": OrderBy,
  "select": Projection,
  "offset": integer,
  "limit": integer,
  "config": QueryConfig
}

Referenced in

Example

{
  "from": "impressions",
  "get": "product",
  "limit": 20,
  "offset": 10
}

EvaluateGroupedOperation

Availability: API v1

Supported query to be evaluated in EvaluateGroupedQuery. Currently only support Generic query and Recommend query

Example

{
  "from": "impressions",
  "goal": {
    "purchase": "true"
  },
  "recommend": "product",
  "where": {
    "product.name": {
      "$get": "query"
    },
    "session.user": {
      "$get": "session.user"
    }
  }
}

More examples

{
  "from": "impressions",
  "get": "product",
  "orderBy": {
    "$p": {
      "purchase": true
    }
  },
  "where": {
    "product.name": {
      "$get": "query"
    },
    "session.user": {
      "$get": "session.user"
    }
  }
}

EvaluateGroupedQuery

Availability: API v1

The EvaluateGroupedQuery is similar to the EvaluateQuery with an addition option to group multiple entries into a single test case.

For example, if there exists a "customerCohort" identifier in "impressions" table, we can evaluate by the customerCohort instead of the individual customer with the following EvaluateGroupedQuery:

{
  "evaluate": {
    "from": "impressions",
    "where": {
      "customer": { "$get": "customer" }
    },
    "recommend": "product",
    "goal": { "purchase": true }
  },
  "group": "customerCohort",
  "test": {
    "customerCohort": { "$gte": 5 }
  },
  "select": ["trainSamples", "testSamples", "meanRank"]
}

Format

{
  "train": Proposition,
  "test": Proposition,
  "testSource": TestSource,
  "select": Selection,
  "maxTime": integer,
  "group": string,
  "goal": Proposition,
  "evaluate": EvaluateGroupedOperation
}

Referenced in

Example

{
  "evaluate": {
    "from": "impressions",
    "goal": {
      "purchase": "true"
    },
    "recommend": "product",
    "where": {
      "product.name": {
        "$get": "query"
      },
      "session.user": {
        "$get": "session.user"
      }
    }
  },
  "group": "userGroup",
  "select": [
    "accuracy",
    "meanRank",
    "n"
  ],
  "test": {
    "userGroup": {
      "$gte": 5
    }
  }
}

EvaluateMatch

Availability: API v1

A Match query to be evaluated in the Match query

Format

{
  "from": From,
  "where": Proposition,
  "select": Projection,
  "match": Get,
  "basedOn": PropositionSet,
  "offset": integer,
  "limit": integer,
  "config": QueryConfig
}

Referenced in

Example

{
  "from": "impressions",
  "limit": 2,
  "match": "prevProduct",
  "offset": 2,
  "select": [
    "title",
    "description",
    "price"
  ],
  "where": {
    "customer": 4,
    "query": "laptop"
  }
}

EvaluateMultiGenericQuery

Availability: API v1

The Generic Query to be evaluated in a EvaluateGroupedQuery

Format

{
  "from": From,
  "where": Proposition,
  "get": Get,
  "orderBy": OrderBy,
  "select": Projection,
  "offset": integer,
  "limit": integer
}

Example

{
  "from": "impressions",
  "get": "product",
  "orderBy": {
    "$p": {
      "purchase": true
    }
  },
  "where": {
    "product.name": {
      "$get": "query"
    },
    "session.user": {
      "$get": "session.user"
    }
  }
}

EvaluateOperation

Availability: API v1

Operation to be evaluated.

Referenced in

Example

{
  "from": "messages",
  "get": "product",
  "similarity": {
    "description": {
      "$get": "message"
    },
    "title": {
      "$get": "message"
    }
  }
}

More examples

{
  "from": "products",
  "get": "product",
  "orderBy": "$p",
  "where": {
    "name": {
      "$get": "name"
    }
  }
}
{
  "from": "products",
  "predict": "category",
  "where": {
    "name": {
      "$get": "name"
    }
  }
}
{
  "from": "messages",
  "match": "product",
  "where": {
    "message": {
      "$get": "message"
    }
  }
}

EvaluatePredict

Availability: API v1

A Predict query to be evaluated in the Evaluate query

Format

{
  "from": From,
  "where": Proposition,
  "predict": PropositionSet,
  "basedOn": PropositionSet,
  "exclusiveness": boolean,
  "select": Projection,
  "offset": integer,
  "limit": integer,
  "config": QueryConfig
}

Referenced in

Example

{
  "from": "products",
  "predict": "category",
  "where": {
    "name": {
      "$get": "name"
    }
  }
}

EvaluateQuery

Availability: API v1

A query to evaluate:

Format

{
  "train": Proposition,
  "test": Proposition,
  "testSource": TestSource,
  "select": Selection,
  "maxTime": integer,
  "evaluate": EvaluateOperation
}

Referenced in

Example

{
  "evaluate": {
    "from": "products",
    "predict": "category",
    "where": {
      "name": {
        "$get": "name"
      }
    }
  },
  "select": [
    "accuracy",
    "meanRank",
    "n"
  ],
  "test": {
    "$index": {
      "$mod": [
        10,
        1
      ]
    }
  }
}

EvaluateRecommend

Availability: API v1

A Recommend query to be evaluated in the Evaluate query

Format

{
  "from": From,
  "where": Proposition,
  "recommend": Get,
  "goal": Proposition,
  "select": Projection,
  "offset": integer,
  "limit": integer
}

Example

{
  "from": "impressions",
  "goal": {
    "purchase": "true"
  },
  "recommend": "product",
  "where": {
    "product.name": {
      "$get": "query"
    },
    "session.user": {
      "$get": "session.user"
    }
  }
}

EvaluateSimilarity

Availability: API v1

A Similarity query to be evaluated in the Evaluate query

Format

{
  "from": From,
  "where": Proposition,
  "get": Get,
  "similarity": Proposition or PrimitiveProposition,
  "select": Projection,
  "offset": integer,
  "limit": integer
}

Referenced in

Example

{
  "from": "messages",
  "get": "product",
  "similarity": {
    "description": {
      "$get": "message"
    },
    "title": {
      "$get": "message"
    }
  }
}

ExponentPropositionArray

Availability: API v1

Define the base and the exponent of the $pow operator in the array format.

The first item of the array is the base and the second item of the array is the exponent.

Referenced in

Example

[
  "width",
  2
]

ExponentPropositionObject

Availability: API v1

Define the base and the exponent of the $pow operator in the object format.

Format

{
  "base": Score,
  "exponent": Score
}

Referenced in

Example

{
  "base": "width",
  "exponent": 2
}

EmptyDocument

Availability: API v1

The empty response object may contain more information in the future.

Referenced in

  • /api/v1/schema/_rename
  • /api/v1/schema/_copy

FieldProposition

Availability: API v1 · API v2 (beta)

FieldProposition expresses statements about a field in a table.

For example, the following expression

"price": {"$lt": 500 }

describes a statement that price is under 500.

Format

{
  "fieldName": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "from": "impressions",
  "where": {
    "click": true
  }
}

More examples

"impressions"
{
  "from": {
    "from": "impressions",
    "where": {
      "click": true
    }
  },
  "orderBy": "$p",
  "where": {
    "query": "laptop"
  }
}
{
  "from": "impressions"
}

FromTablemodify

Availability: API v1 · API v2 (beta)

From expression declares the used table

Example

"impressions"

More examples

"products"
"customers"
"messages"

FromTablequery

Availability: API v1

From expression declares the examined table.

Referenced in

Example

"impressions"

More examples

"products"
"customers"
"messages"

FromWhere

Availability: API v1

FromWhere expression allows you to narrow the examined table.

When using the FromWhere, Aito would only consider that narrowed slice of table.

For instance, this query:

{
  "from": {
    "from": "impressions",
    "where": {
      "context.user": "larry"}
  },
 "match": "product"
}

is different from:

{
  "from": "impressions",
  "where": {
      "context.user": "larry"
  },
 "match": "product"
}

In the first query, Aito matches Larry with products only based on Larry impressions data while in the second query, Aito matches Larray with products based on Larry and other users' impressions data.

Format

{
  "from": From,
  "where": Proposition,
  "limit": integer
}

Referenced in

Example

{
  "from": "impressions",
  "where": {
    "click": true
  }
}

Get

Availability: API v1

Get expression defines what items are returned as query results.

By default, the hits are from the table defined in "from" clause. In some cases, you may want to declare propositions like 'query is laptop' in impression table, while returning results from the separate products table, based on click likelihood. In this case, you may have query such as

{
  "from": "impressions",
  "where": { "query": "laptop" },
  "get": "product",
  "orderBy": {
    "$p": {
      "$context": { "click": true }
    }
  }
}

The "get" expression takes a field name as a parameter. If the field is link, the returned results are from the linked table. If the field is not link, the field values are returned as results.

Normally, the result of a query consists of the field values that best fulfill the query conditions. Field analyzers extract features from text fields and the $feature property can be used to return features instead of complete field values. For instance, the following example demonstrates how to discover product tags which are likely to lead to sales

{
  "from": "impressions",
  "where": { "query": "cheap phone" },
  "get": "product.tags.$feature",
  "orderBy": {
    "$p": {
      "$context": { "click": true }
    }
  }
}

The $feature syntax also allows you to examine the values/features of a link field like it would be a regular field.

Example

"product"

More examples

"user"
"text.$feature"
"link.field"

GetValueExpression

Availability: API v1 · API v2 (beta)

$get is used to access external variables in the evaluate query.

$get is currently only used in the the Evaluate queries. The evaluate tests a specified query by examining the table rows one-by-one. $get allows accessing the tested row's properties.

Consider the following example.

Given a table containing products data with the following schema:

"products": {
  "type": "table",
  "columns": {
    "title": { "type": "Text", "analyzer": "English" },
    "description": { "type": "Text", "analyzer": "English" }
  }
}

and a table containing impressions data with the following schema:

"impressions": {
  "type": "table",
  "columns": {
    "customer": { "type": "Int", "link": "customers.id" },
    "product": { "type": "Int", "link": "products.id" },
    "query": { "type": "Text", "analyzer": "English" },
  }
}

The goal is to test how well the traditional TF-IDF similarity metric works for finding a product. The $get is used in the similarity query to compare the product's title and description fields with the impression table's query field.

{
  "test": {
    "click": true
  },
  "evaluate": {
    "from": "impressions",
    "get": "product",
    "similarity": {
      "title": { "$get": "query" },
      "description": { "$get": "query" }
    }
  },
  "select": ["trainSamples", "n", "accuracy", "baseAccuracy", "meanRank", "mxe"]
}

Format

{
  "$get": string
}

Example

{
  "$get": "query"
}

More examples

{
  "$get": "click"
}
{
  "$get": "product.title"
}

Goal

Availability: API v1

Specifies a goal to maximize.

Results are ordered by the likelihood of the goal in descending order.

Referenced in

Example

{
  "purchase": true
}

More examples

{
  "click": true
}

Hits

Availability: API v1

Entries returned for a given query.

Referenced in

Example

[
  {
    "$p": 0.16772371915637704,
    "category": "100",
    "id": "6410405060457",
    "name": "Pirkka bio cherry tomatoes 250g international 1st class",
    "price": 1.29,
    "tags": "fresh vegetable pirkka tomato"
  },
  {
    "$p": 0.16772371915637704,
    "category": "100",
    "id": "6410405093677",
    "name": "Pirkka iceberg salad Finland 100g 1st class",
    "price": 1.29,
    "tags": "fresh vegetable pirkka"
  }
]

Is

Availability: API v1 · API v2 (beta)

The syntax {"field": { "$is": "yourvalue" } } is equivalent to { "field": "yourvalue" }.

Format

{
  "$is": PrimitiveProposition
}

Referenced in

Example

{
  "$is": "value"
}

KnnPropositionArray

Availability: API v1 · API v2 (beta)

Define the 'k' and the 'near' parameter of the $knn operator in the array format.

The first item of the array is the 'k' parameter and the second item of the array is the 'near' parameter.

Referenced in

Example

[
  4,
  {
    "tags": "laptop"
  }
]

KnnPropositionObject

Availability: API v1 · API v2 (beta)

Define the 'k' and the 'near' parameter of the $knn operator in the object format.

Format

{
  "k": integer,
  "near": Proposition or PrimitiveProposition
}

Referenced in

Example

{
  "k": 4,
  "near": {
    "tags": "laptop"
  }
}

NnPropositionArray

Availability: API v1 · API v2 (beta)

Define the 'near' and 'threshold' the parameters of the $nn operator in the array format.

The first item of the array is the 'near' parameter and the second item of the array is the 'threshold' parameter.

Referenced in

Example

[
  {
    "tags": "laptop"
  }
]

NnPropositionObject

Availability: API v1 · API v2 (beta)

Define the 'near' and the 'threshold' parameters of the $nn operator in the object format.

Format

{
  "near": Proposition or PrimitiveProposition,
  "threshold": number
}

Referenced in

Example

{
  "near": {
    "tags": "laptop"
  }
}

ModPropositionArray

Availability: API v1 · API v2 (beta)

Define the divisor and the remainder of the $mod operator in the array format.

The first item of the array is the divisor and the second item of the array is the remainder.

Referenced in

Example

[
  2,
  0
]

ModPropositionObject

Availability: API v1 · API v2 (beta)

Define the divisor and the remainder of the $mod operator in the object format.

Format

{
  "divisor": integer,
  "remainder": integer
}

Referenced in

Example

{
  "divisor": 2,
  "remainder": 0
}

OnPropositionArray

Availability: API v1 · API v2 (beta)

Define the hypothesis and the conditional of the $on operator in the array format.

The first item of the array is the hypothesis and the second item of the array is the condition.

Referenced in

Example

[
  {
    "click": true
  },
  {
    "user.tags": "nyc"
  }
]

OnPropositionObject

Availability: API v1 · API v2 (beta)

Define the hypothesis and the conditional of the $on operator in the object format.

Format

{
  "prop": Proposition,
  "on": Proposition
}

Referenced in

Example

{
  "on": {
    "user.tags": "nyc"
  },
  "prop": {
    "click": true
  }
}

OrderBy

Availability: API v1

Declares the sorting order of the result by a field or by a user-defined score.

Example

"product.price"

More examples

{
  "$asc": "product.price"
}
{
  "$desc": "product.price"
}
{
  "$multiply": [
    "$p",
    "prices"
  ]
}

PrimitiveProposition

Availability: API v1 · API v2 (beta)

PrimitiveProposition states a field's value.

It should always be used inside a field declaration of a document proposition. For example, in the proposition { "field": "value" } the string "value" is the primitive proposition.

Example

4

More examples

3.1
false
null

Proposition

Availability: API v1 · API v2 (beta)

Proposition expression describes a fact, or a statement.

For instance, the following proposition:

  • { "customer.id": 4 } describes a customer with the id of 4
  • { "clicked": true } describes that the customer has clicked the item

You can also combine multiple propositions by declaring them in an object clause. The propositions will be combined by the $and operator. For instance:

{ 
  "price": { 
    "$gt": 20, 
    "$lte": 40 
  } 
}

describes an item of which price is greater than 20 and less than or equal to 40.

This proposition is equivalent to:

{ 
  "price": { 
    "$and": [
      { "$gt": 20 }, 
      { "$lte": 40 }
    ]
  } 
}

This proposition can be used, for example, in a Search Query to find an item that matches this price criteria:

{
  "from": "products",
  "where": {
    "price": { 
      "$gt": 20, 
      "$lte": 40 
    }
  }
}

Example

{
  "customer": 4,
  "query": {
    "$match": "laptop"
  }
}

More examples

{
  "price": {
    "$gte": 50,
    "$lt": 100
  }
}
{
  "tags": {
    "$match": "laptop"
  }
}

PropositionSet

Availability: API v1 · API v2 (beta)

PropositionSet expression is used to describe a collection of propositions. This collection of statements can be the alternative values in a field.

Example

"product.tags"

More examples

"query"
"product"
"tags"

RelateOrderBy

Availability: API v1

Declares the sorting order.

The sorting order can be any attribute of the Relate query hit.

Referenced in

Example

{
  "$desc": "info.miTrue"
}

More examples

{
  "$asc": "lift"
}

ResponseHit

Availability: API v1

Entry returned for a given query.

Example

{
  "name": "My product",
  "price": 172.19
}

More examples

{
  "$score": 0.22350516297675496,
  "$value": "coffee",
  "$why": {
    "factors": [
      {
        "factors": [
          {
            "proposition": {
              "name": {
                "$has": "coffee"
              }
            },
            "type": "relatedPropositionLift",
            "value": 8.45603245079726
          }
        ],
        "proposition": "coffee",
        "type": "hitPropositionLift",
        "value": 8.45603245079726
      }
    ],
    "type": "product"
  }
}

Score

Availability: API v1

Score expression resolves to a numeric score value or probability. All scores can be used in both highlights ($highlight) and explanations ($why).

Example

2

More examples

"product.margin"
"$p"
"$similarity"

Selection

Availability: API v1

Describes the fields and/or built-in attributes to return.

Example

[
  "user.name",
  "query",
  "product.title",
  "click"
]

More examples

[
  "$why"
]
[
  "*"
]
[
  "$score",
  "product.*"
]

TestSource

Availability: API v1

TestSource enables more options to choose the testing data in the Evaluate Query. Using the TestSource, you can specify the testing data as a specific slice of the same table with the training data or of a completely different table.

Format

{
  "from": From,
  "where": Proposition,
  "offset": integer,
  "limit": integer,
  "select": Selection
}

Example

{
  "limit": 100,
  "select": [
    "query"
  ],
  "where": {
    "$index": {
      "$mod": [
        5,
        1
      ]
    }
  }
}

UserDefinedObject

Availability: API v1 · API v2 (beta)

Any object which is valid according to the database schema.

The contents of the object depends on the data inserted into the database. If for example you have a products table which has fields name and price, your object could look like:

{ "name": "My product", "price": 172.19 }

Referenced in

Example

{
  "name": "My product",
  "price": 172.19
}

Value

Availability: API v1

Value expression resolves to a primitive like int or json, score, probability or individual feature.

Value expression can refer to any field in the table with expressions like "query" or "product.price". Value expression can refer to the narrowed document overall likelihood, for example "$p", after "get": "message", to refer the message's likelihood. Value can also refer to the likelihood of a proposition with expressions such as { "$p": { "tags": "cover" } } or { "$p": { "$context": "click" } } to refer to the context table's fields.

Example

"product.id"