Aito SDK
The Aito SDK consists of:
schema: Data structure for the Aito Database Schema
v1: The v1 API client to make requests to an Aito Database Instance
v2: A client for the Aito v2 API
requests: Request objects used in AitoClient request so that you don’t have to worry about the Aito API endpoint
responses: Enriched response objects returned after executing a request with the AitoClient
api: Different useful functions that uses an AitoClient object to interact with an Aito Database Instance
DataFrameHandler: Utility to read, write, and convert a Pandas DataFrame in accordance to a Aito Table Schema
Note
We highly recommend you to take a look at the quickstart guide to uploading data if you haven’t already.
AitoSchema
Before uploading data into Aito, you need to create a table with a AitoTableSchema.
You can infer a table schema from a Pandas DataFrame with infer_from_pandas_data_frame().
You can also create a table schema column-by-column and infer the AitoColumnTypeSchema with infer_from_samples().
AitoClient
The AitoClient offers different functions to send a Request object to your Aito instance.
Make a request:
request()Make a request asynchronously using AIOHTTP ClientSession:
async_request()Bounded asynchronous request with asyncio semaphore:
bounded_async_request()Make multiple requests asynchronously:
batch_requests()
Choosing an API version
Each Aito API version has its own package, whose meaning never changes:
from aito.v1 import Client # the v1 API: /api/v1
from aito.v2 import Client # the v2 API: /api/v2
aito.Client is the one name that follows the default version. It moves only on a
major release of aitoai, so the major version tells you which API it is: 1.x is v2
(0.x was v1). Use aito.Client in quick experiments; in production code import the
explicit version, so an upgrade cannot change the API underneath it. To stay on v1, import
from aito.v1 import Client, or pin aitoai<1.
Before 0.7 the v1 client lived in aito.client and the helpers in aito.api, and the v2
client in aito.client.v2. Those paths were deprecated in 0.7 and removed in 1.0:
importing one raises an ImportError that names its replacement (aito.v1,
aito.v2, aito.v1.api).
The aito command-line tool still talks to the v1 API throughout 1.x (it imports
aito.v1 explicitly, so the default switch does not move it). v2 support arrives as an
opt-in in a 1.x minor release; the CLI’s default moves to v2 only in 2.0.
A bare pip install aitoai installs the API clients only. The command-line tool, schema
inference and file conversion need pip install 'aitoai[cli]'.
AitoClientV2
The AitoClientV2 talks to the v2 API. It is a separate
class from the v1 AitoClient rather than a flag on it, because the two
APIs return genuinely different response shapes — the reasoning is written up in
docs/v2-client-design.md.
from aito.v2 import Client
# the public read-only sandbox; use your own instance URL and key in production
client = Client('https://shared.aito.ai/db/aito-demo',
'yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi', env='v2')
prediction = client.predict(
from_table='invoices', where={'Description': 'cloud services'}, predict='GLCode')
print(prediction.first.value, prediction.first.probability) # E002 0.83...
A predict ranks every value of the field; the evidence in where changes each
candidate’s probability but never removes one. To return only the values actually seen
with the evidence, filter on the per-candidate frequency $f with having, via
query():
seen = client.query({
'from': 'invoices',
'where': {'Processor': 'Emily Davis'},
'predict': 'GLCode',
'select': ['$value', '$p', '$f'],
'having': {'$f': {'$gte': 1}},
})
print([(hit.value, hit['$f']) for hit in seen]) # [('F001', 20)]
having filters the ranked list after scoring: the remaining $p values are not
renormalised, and $f is the only field it accepts — {'$f': {'$gte' | '$gt' | '$lte' |
'$lt': <number>}}. Filtering on anything else, such as $p, is a 400
request.invalid.
Querying:
Predict a field’s value:
predict()Retrieve rows:
search()Rank values by a goal:
recommend()Find statistical relationships:
relate()Match a link field’s candidates against evidence:
match()Estimate a numeric field:
estimate()Aggregate:
aggregate()Evaluate prediction quality:
evaluate()Anything else, via the universal
_queryendpoint:query()
Note
The named methods post to v2’s enforced named endpoints, which validate that the body
matches the operation. A mismatch is a 400 naming the endpoint that wants that body,
rather than a query that silently does something else.
Manipulating the database:
Note
These operations require the client to be setup with the READ-WRITE API key
Create a collection:
create_collection()Delete a collection:
delete_collection()Upload batches of entries:
upload_entries()Rebuild the index after a bulk load:
optimize()Branch an environment:
branch_env()
Errors carry a machine-readable code, so you branch on the code rather than on the text of the message:
from aito.v2 import Error
try:
client.delete_collection('invoices')
except Error as err:
if not err.is_not_found: # a 404 here is the ordinary "drop if exists" case
raise
Responses carry the engine’s non-fatal warnings, which are the only in-band signal that the server answered a slightly different query than the one you sent:
res = client.query({'from': 'invoices', 'where': {'no_such_column': 'x'}})
for warning in res.warnings:
print(warning.code, warning.message)
# or make it a hard failure:
strict = Client(instance_url, api_key, on_warning='raise')
Aito reports its own server-side processing time in the x-aitoai-response-time header,
which is what an application should surface rather than the round trip. The parsed body does
not carry it, so pass on_response:
timings = []
client = Client(instance_url, api_key,
on_response=lambda resp, path: timings.append(
(path, float(resp.headers['x-aitoai-response-time']))))
A complete runnable example — create a collection, load it, predict, explain, evaluate, drop it
— is in examples/v2_quickstart.py.
AitoAPI
aito.v1.api module offers different functions that takes a Aito Client object as the first argument
Manipulate the database:
Note
These operations require the client to be setup with the READ-WRITE API key
Create a table:
create_table()Delete a table:
delete_table()Create the database:
create_database()Delete the database:
delete_database()Copy a table:
copy_table()Rename a table:
rename_table()Upload the data:
Note
These operations require the client to be setup with the READ-WRITE API key
Upload a binary file object to a table:
upload_binary_file()Upload a file to a table:
upload_file()Upload batches of entries to a table:
upload_entries()Optimize a table after uploading the data:
optimize_table()Get information about the database:
Get the instance version:
get_version()Check if a table exists in the instance:
check_table_exists()Get a list of existing tables in the instance:
get_existing_tables()Get a table schema:
get_table_schema()Find the number of entries in a table:
get_table_size()Get the database schema:
get_database_schema()Querying:
Query entries of a table:
query_entries()Query all entries of a table:
query_all_entries()Download a table:
download_table()Make a job request (for query that takes longer than 30 seconds):
job_request()Make a job request step by step:
create_job(),get_job_status(),get_job_result()
Troubleshooting
The easiest way to troubleshoot the Aito SDK is by enabling the debug logging. You can enable the debug logging by:
import logging
logging.basicConfig(level=logging.DEBUG)