Quail
Architecture

Physical plans

A physical plan specifies which operators execute a query, what data each operator receives, and what data it produces. An operator performs one part of the query, such as classifying reviews or selecting result columns. SQL functions describe what a query requests. Physical operators specify how Quail executes that work. The plan also records execution settings, such as the attention path used by a model operator.

The optimizer builds the physical plan from a logical plan. The logical plan describes the requested operations. The physical plan specifies how Quail executes them.

Execute a review query

For example, imagine a reviews table with an id column for review identifiers and a body column for review text. This query classifies each review as positive or negative and returns only negative reviews:

SELECT r.id,
       AI.CLASSIFY(
           PROMPT('What sentiment does this review express? {0}', r.body),
           ARRAY['positive', 'negative']) AS sentiment
FROM reviews r
WHERE AI.CLASSIFY(
    PROMPT('What sentiment does this review express? {0}', r.body),
    ARRAY['positive', 'negative']) IN ('negative');

Before execution, Quail tokenizes the review text. During execution, it identifies each review by its row position in the input table, starting at zero. Quail calls this position a document ID. It is separate from the value in reviews.id.

Quail uses four operators to execute this query. Each box represents an operator. Each arrow shows the data passed between operators.

flowchart TD
  scan["Scan"]
  classify["AiClassify"]
  filter["Filter"]
  project["Project"]
  scan -->|Document IDs| classify
  classify -->|Document IDs and labels| filter
  filter -->|Document IDs for negative reviews| project
  classify -->|Document IDs and labels| project
  1. Scan returns the document IDs for the reviews input.
  2. AiClassify receives these IDs and uses the model to classify the corresponding reviews. It produces a table of document IDs and labels.
  3. Filter reads that table and keeps the document IDs whose label is negative. This comparison runs on the CPU.
  4. Project receives the selected document IDs and the classification table. It reads reviews.id for each selected review and adds the classification label. The result has id and sentiment columns.

The SELECT and WHERE expressions use the same classification output. Quail does not classify each review again for the SELECT expression.

The arrows show which inputs each operator needs. Compatible operators can pass batches to each other before they finish processing all rows. See Execution for how Quail groups and schedules these operators.

Window execution

Window functions run on the CPU and reuse computed AI outputs. They do not call the model again, even when several windows read the same row.

Note that using LIMIT can reduce the number of rows processed by window functions. It does not reduce the number of rows evaluated by AI functions. See Window rules for details.

Inspect the plan

Call query.explain() to inspect the plan without running model inference. The output shows the operators, their execution settings, and estimated work.

Editing a plan

Call query.plan() to get a plan that you can edit before execution. Each edit returns a new plan. You can execute it with query.run(plan=edited).

See Editing physical plans for a complete example that inspects a plan, inserts an operator, and removes it.

To implement an operator, see Custom operators. That guide explains how operator classes declare their inputs, outputs, and execution code.

On this page