> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gp.scale.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Query Language Reference

> Deep dive into QueryAST for building powerful evaluation queries

The QueryAST (Query Abstract Syntax Tree) is a SQL-like query language for aggregating and filtering evaluation data in dashboard widgets. This guide covers the complete query syntax and advanced features.

## Query Basics

### When Are Queries Required?

Queries are required for data-driven widgets:

* **METRIC**: Requires a MetricQuery (single aggregation)
* **TABLE**: Requires a SeriesQuery (multiple rows/columns)
* **BAR**: Requires a SeriesQuery (grouped data)
* **HISTOGRAM**: Requires a SeriesQuery (distribution data)
* **DONUT**: Requires a SeriesQuery (grouped data for slices)
* **SCATTER**: Requires a SeriesQuery (two or more numeric columns)
* **TIMESERIES**: Requires a SeriesQuery (aggregations over time)

Queries are NOT needed for:

* **MARKDOWN**: Static content only
* **HEADING**: Text display only

### Data Sources

QueryAST can access two data sources for each evaluation item:

**`data.*` - User-defined data**

* Custom fields you provided when creating the evaluation
* Examples: `data.input`, `data.expected_output`, `data.category`, `data.score`

**`task_result_cache.*` - Task execution results**

* Results from evaluation tasks (chat completions, agent runs, etc.)
* Examples: `task_result_cache.llm_score`, `task_result_cache.latency_ms`, `task_result_cache.metadata.confidence`

<Info>
  Both data sources support nested fields using dot notation. For example, `data.metadata.model_version` or `task_result_cache.output.reasoning`.
</Info>

### Query Structure Overview

A query is a JSON object defining what data to select, how to aggregate it, and what filters to apply:

```json theme={null}
{
  "select": [...],      // Columns and aggregations to return
  "filter": {...},      // Optional WHERE clause conditions
  "groupBy": [...],     // Optional GROUP BY columns
  "orderBy": [...],     // Optional sorting
  "limit": 100          // Optional row limit
}
```

***

## Query Types

### MetricQuery

Returns a single scalar value. Used exclusively for METRIC widgets.

**Structure:**

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG|SUM|COUNT|...",
        "column": "column_name",
        "source": "data|task_result_cache"
      },
      "alias": "optional_alias"
    }
  ],
  "filter": { /* optional */ }
}
```

**Constraints:**

* Select clause must have exactly one item
* That item must be an `AGGREGATION` (not a raw `COLUMN`)
* No `GROUP BY`, `ORDER BY`, or `LIMIT` allowed

#### Example: Average Score

**Example:**

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "score",
        "source": "data"
      },
      "alias": "avg_score"
    }
  ],
  "filter": {
    "conditions": [
      {
        "column": "category",
        "source": "data",
        "operator": "=",
        "value": "test"
      }
    ]
  }
}
```

**SQL Equivalent:**

```sql theme={null}
SELECT AVG(data->>'$.score') AS avg_score
FROM evaluation_items
WHERE data->>'$.category' = 'test'
```

### SeriesQuery

Returns multiple rows and columns. Used for `TABLE`, `BAR`, `HISTOGRAM`, `DONUT`, `SCATTER`, and `TIMESERIES` widgets.

**Structure:**

```json theme={null}
{
  "select": [
    // Mix of columns and aggregations
  ],
  "filter": { /* optional */ },
  "groupBy": [ /* optional column names */ ],
  "orderBy": [ /* optional sort specs */ ],
  "limit": 100 // optional
}
```

**Constraints:**

* Select clause must have at least one item
* Can mix `COLUMN` and `AGGREGATION` expressions
* When using `GROUP BY`, non-aggregated columns must be in the `groupBy` list

#### Example: Performance by Category

**Example:**

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "COLUMN",
        "column": "category",
        "source": "data"
      }
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "score",
        "source": "data"
      },
      "alias": "avg_score"
    }
  ],
  "groupBy": ["category"],
  "orderBy": [
    {
      "column": "avg_score",
      "direction": "DESC"
    }
  ],
  "limit": 10
}
```

**SQL Equivalent:**

```sql theme={null}
SELECT 
  data->>'$.category' AS category,
  AVG(data->>'$.score') AS avg_score
FROM evaluation_items
GROUP BY data->>'$.category'
ORDER BY avg_score DESC
LIMIT 10
```

***

## `evaluation_ids` (Evaluation Group Dashboards)

When building queries for [evaluation group dashboards](./eval-group-dashboards), you can control which evaluations in the group to include using the `evaluation_ids` field.

### Query-Level `evaluation_ids`

Add `evaluation_ids` at the top level of a query to scope it to specific evaluations in the group. If omitted, all evaluations in the group are included.

```json theme={null}
{
  "select": [
    {
      "expression": {"type": "AGGREGATION", "function": "AVG", "column": "score", "source": "data"},
      "alias": "avg_score"
    }
  ],
  "evaluation_ids": ["eval-abc", "eval-def"]
}
```

### Per-Aggregation `evaluation_ids`

Individual aggregation expressions can specify their own `evaluation_ids` to narrow the scope further. These must be a subset of the query-level `evaluation_ids`.

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "score",
        "source": "data",
        "evaluation_ids": ["eval-abc"]
      },
      "alias": "eval_a_avg"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "score",
        "source": "data",
        "evaluation_ids": ["eval-def"]
      },
      "alias": "eval_b_avg"
    }
  ],
  "evaluation_ids": ["eval-abc", "eval-def"]
}
```

<Info>
  The special `_evaluation_id` column is automatically available in evaluation group dashboard queries. You can use it in `SELECT` and `GROUP BY` to break down data by evaluation source. See the [Evaluation Group Dashboards](./eval-group-dashboards) guide for details.
</Info>

***

## `SELECT` Clause

The `SELECT` clause defines what columns or aggregations to return.

### Column Expression

Reference a raw column from the data without aggregation.

```json theme={null}
{
  "expression": {
    "type": "COLUMN",
    "column": "category",
    "source": "data"
  },
  "alias": "category_name"  // Optional alias
}
```

**Fields:**

* `type`: Always "COLUMN"
* `column`: Name of the column to select
* `source`: "data" or "task\_result\_cache" (optional, defaults to "data")
* `alias`: Optional name for the result column (recommended for aggregation columns)

<Tip>
  Aliases are especially useful for aggregation columns -- they provide readable column headers in tables, disambiguate when multiple aggregations use the same column, and are required for meaningful labels in chart legends.
</Tip>

### Aggregation Expression

Apply an aggregation function to compute a derived value.

```json theme={null}
{
  "expression": {
    "type": "AGGREGATION",
    "function": "AVG",
    "column": "score",
    "source": "data",
    "params": {}  // Optional parameters for certain functions
  },
  "alias": "average_score"
}
```

**Fields:**

* `type`: Always "AGGREGATION"
* `function`: One of the supported aggregation functions (see below)
* `column`: Column to aggregate, or `"*"` for `COUNT(*)`
* `source`: "data" or "task\_result\_cache" (optional)
* `params`: Function-specific parameters (for `PERCENTILE` and `PERCENTAGE`)
* `alias`: Optional name for the result

***

## Aggregation Functions

### `COUNT`

Count the number of rows.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "COUNT",
  "column": "*"
}
```

**Use Cases:**

* Total number of items
* Items per category (with `GROUP BY`)
* Items matching filter criteria

### `SUM`

Sum all values in a column.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "SUM",
  "column": "cost",
  "source": "task_result_cache"
}
```

**Use Cases:**

* Total cost across all items
* Total tokens used
* Cumulative metrics

### `AVG`

Calculate the mean value.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "AVG",
  "column": "score",
  "source": "data"
}
```

**Use Cases:**

* Average score
* Mean latency
* Average confidence

### `MIN` / `MAX`

Find the minimum or maximum value.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "MAX",
  "column": "latency_ms",
  "source": "task_result_cache"
}
```

**Use Cases:**

* Worst-case latency
* Best score achieved
* Range calculations

### `STDDEV` / `VARIANCE`

Calculate standard deviation or variance.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "STDDEV",
  "column": "score",
  "source": "data"
}
```

**Use Cases:**

* Measure score consistency
* Identify high-variance categories
* Quality control metrics

### `PERCENTILE`

Calculate a specific percentile value.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "PERCENTILE",
  "column": "latency_ms",
  "source": "task_result_cache",
  "params": {
    "percentile": 95
  }
}
```

**Parameters:**

* `percentile`: Number between 0 and 100 (required)

**Use Cases:**

* P95/P99 latency tracking
* Tail performance analysis
* SLA monitoring

### `COUNT_DISTINCT`

Count unique values in a column.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "COUNT_DISTINCT",
  "column": "user_id",
  "source": "data"
}
```

**Use Cases:**

* Number of unique users
* Distinct categories present
* Cardinality checks

### `PERCENTAGE`

Calculate percentage of rows matching filter criteria.

```json theme={null}
{
  "type": "AGGREGATION",
  "function": "PERCENTAGE",
  "column": "*",
  "params": {
    "percentage_filters": {
      "conditions": [
        {
          "column": "score",
          "source": "data",
          "operator": ">=",
          "value": 0.7
        }
      ]
    }
  }
}
```

**Parameters:**

* `percentage_filters`: Filter object defining which rows to count (required)

**Use Cases:**

* Pass/fail rates
* Percentage above threshold
* Compliance metrics

***

## Filter Clause (`WHERE`)

Filter clauses narrow down which rows to include in computations.

### Basic Filter

Single condition:

```json theme={null}
{
  "filter": {
    "conditions": [
      {
        "column": "category",
        "source": "data",
        "operator": "=",
        "value": "quality"
      }
    ]
  }
}
```

### Multiple Conditions

Combine conditions with logical operators:

```json theme={null}
{
  "filter": {
    "conditions": [
      {
        "column": "score",
        "source": "data",
        "operator": ">=",
        "value": 0.5
      },
      {
        "column": "category",
        "source": "data",
        "operator": "=",
        "value": "production"
      }
    ],
    "logicalOperators": ["AND"]
  }
}
```

<Warning>
  The number of logical operators must be exactly `len(conditions) - 1`. For 3 conditions, you need 2 operators.
</Warning>

### Comparison Operators

| Operator   | Description         | Example Value             |
| ---------- | ------------------- | ------------------------- |
| `=`        | Equals              | `"test"` or `42`          |
| `!=`       | Not equals          | `"draft"`                 |
| `>`        | Greater than        | `0.5`                     |
| `<`        | Less than           | `100`                     |
| `>=`       | Greater or equal    | `0.7`                     |
| `<=`       | Less or equal       | `1.0`                     |
| `IN`       | In list             | `["cat1", "cat2"]`        |
| `NOT IN`   | Not in list         | `["archived", "deleted"]` |
| `LIKE`     | Substring match     | `"%error%"`               |
| `NOT LIKE` | Not substring match | `"%deprecated%"`          |

### Complex Filter Example

Combine multiple conditions with AND/OR logic:

```json theme={null}
{
  "filter": {
    "conditions": [
      {
        "column": "score",
        "source": "data",
        "operator": ">=",
        "value": 0.7
      },
      {
        "column": "category",
        "source": "data",
        "operator": "IN",
        "value": ["quality", "accuracy"]
      },
      {
        "column": "status",
        "source": "data",
        "operator": "!=",
        "value": "archived"
      }
    ],
    "logicalOperators": ["AND", "AND"]
  }
}
```

This evaluates as: `(score >= 0.7) AND (category IN ['quality', 'accuracy']) AND (status != 'archived')`

<Info>
  Logical operators are evaluated left-to-right without precedence. The expression `A AND B OR C` evaluates as `((A AND B) OR C)`.
</Info>

***

## `GROUP BY` Clause

Group rows by one or more columns before applying aggregations.

### Single Column Grouping

```json theme={null}
{
  "select": [
    {
      "expression": {"type": "COLUMN", "column": "category", "source": "data"}
    },
    {
      "expression": {"type": "AGGREGATION", "function": "COUNT", "column": "*"},
      "alias": "count"
    }
  ],
  "groupBy": ["category"]
}
```

**SQL Equivalent:**

```sql theme={null}
SELECT 
  data->>'$.category' AS category,
  COUNT(*) AS count
FROM evaluation_items
GROUP BY data->>'$.category'
```

### Multi-Column Grouping

Group by multiple dimensions:

```json theme={null}
{
  "select": [
    {
      "expression": {"type": "COLUMN", "column": "model", "source": "data"}
    },
    {
      "expression": {"type": "COLUMN", "column": "category", "source": "data"}
    },
    {
      "expression": {"type": "AGGREGATION", "function": "AVG", "column": "score", "source": "data"},
      "alias": "avg_score"
    }
  ],
  "groupBy": ["model", "category"]
}
```

**SQL Equivalent:**

```sql theme={null}
SELECT 
  data->>'$.model' AS model,
  data->>'$.category' AS category,
  AVG(data->>'$.score') AS avg_score
FROM evaluation_items
GROUP BY data->>'$.model', data->>'$.category'
```

<Tip>
  When using `GROUP BY`, all non-aggregated columns in `SELECT` must appear in the `groupBy` array.
</Tip>

***

## `ORDER BY` Clause

Sort results by one or more columns.

### Basic Sorting

```json theme={null}
{
  "orderBy": [
    {
      "column": "avg_score",
      "direction": "DESC"
    }
  ]
}
```

**Directions:**

* `ASC`: Ascending (smallest to largest)
* `DESC`: Descending (largest to smallest)

### Multi-Column Sorting

Sort by multiple columns with different directions:

```json theme={null}
{
  "orderBy": [
    {
      "column": "category",
      "direction": "ASC"
    },
    {
      "column": "avg_score",
      "direction": "DESC"
    }
  ]
}
```

This sorts by category alphabetically, then by avg\_score descending within each category.

***

## `LIMIT` Clause

Restrict the number of rows returned.

```json theme={null}
{
  "limit": 20
}
```

**Use Cases:**

* Top-N queries (e.g., "Top 10 Items")
* Prevent overwhelming table displays
* Performance optimization for large datasets

**Example: Top 5 Categories**

```json theme={null}
{
  "select": [
    {"expression": {"type": "COLUMN", "column": "category", "source": "data"}},
    {"expression": {"type": "AGGREGATION", "function": "AVG", "column": "score", "source": "data"}, "alias": "avg_score"}
  ],
  "groupBy": ["category"],
  "orderBy": [{"column": "avg_score", "direction": "DESC"}],
  "limit": 5
}
```

***

## Advanced Examples

### Example 1: Multi-Dimensional Performance Table

Break down performance by model and category with multiple statistics.

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "COLUMN",
        "column": "model",
        "source": "data"
      }
    },
    {
      "expression": {
        "type": "COLUMN",
        "column": "category",
        "source": "data"
      }
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "COUNT",
        "column": "*"
      },
      "alias": "count"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "score",
        "source": "data"
      },
      "alias": "avg_score"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "STDDEV",
        "column": "score",
        "source": "data"
      },
      "alias": "stddev_score"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "MIN",
        "column": "score",
        "source": "data"
      },
      "alias": "min_score"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "MAX",
        "column": "score",
        "source": "data"
      },
      "alias": "max_score"
    }
  ],
  "groupBy": ["model", "category"],
  "orderBy": [
    {
      "column": "model",
      "direction": "ASC"
    },
    {
      "column": "avg_score",
      "direction": "DESC"
    }
  ]
}
```

### Example 2: Filtered Percentile Calculation

Calculate P95 score for only production items.

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "PERCENTILE",
        "column": "latency_ms",
        "source": "task_result_cache",
        "params": {
          "percentile": 95
        }
      },
      "alias": "p95_latency"
    }
  ],
  "filter": {
    "conditions": [
      {
        "column": "environment",
        "source": "data",
        "operator": "=",
        "value": "production"
      },
      {
        "column": "latency_ms",
        "source": "task_result_cache",
        "operator": ">",
        "value": 0
      }
    ],
    "logicalOperators": ["AND"]
  }
}
```

### Example 3: Complex Filter with IN and LIKE

Find items in specific categories containing certain text.

```json theme={null}
{
  "select": [
    {
      "expression": {"type": "COLUMN", "column": "input", "source": "data"}
    },
    {
      "expression": {"type": "COLUMN", "column": "category", "source": "data"}
    },
    {
      "expression": {"type": "COLUMN", "column": "score", "source": "data"}
    }
  ],
  "filter": {
    "conditions": [
      {
        "column": "category",
        "source": "data",
        "operator": "IN",
        "value": ["quality", "accuracy", "helpfulness"]
      },
      {
        "column": "input",
        "source": "data",
        "operator": "LIKE",
        "value": "%customer support%"
      }
    ],
    "logicalOperators": ["AND"]
  },
  "orderBy": [
    {
      "column": "score",
      "direction": "DESC"
    }
  ],
  "limit": 20
}
```

### Example 4: Pass/Fail Rate by Model

Calculate success rates grouped by model.

```json theme={null}
{
  "select": [
    {
      "expression": {"type": "COLUMN", "column": "model", "source": "data"}
    },
    {
      "expression": {"type": "AGGREGATION", "function": "COUNT", "column": "*"},
      "alias": "total"
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "PERCENTAGE",
        "column": "*",
        "params": {
          "percentage_filters": {
            "conditions": [
              {
                "column": "score",
                "source": "data",
                "operator": ">=",
                "value": 0.7
              }
            ]
          }
        }
      },
      "alias": "pass_rate"
    }
  ],
  "groupBy": ["model"],
  "orderBy": [
    {
      "column": "pass_rate",
      "direction": "DESC"
    }
  ]
}
```

### Example 5: Nested Data Access

Query nested fields using dot notation.

```json theme={null}
{
  "select": [
    {
      "expression": {
        "type": "COLUMN",
        "column": "metadata.model_version",
        "source": "data"
      }
    },
    {
      "expression": {
        "type": "AGGREGATION",
        "function": "AVG",
        "column": "output.confidence",
        "source": "task_result_cache"
      },
      "alias": "avg_confidence"
    }
  ],
  "groupBy": ["metadata.model_version"]
}
```

This accesses:

* `data.metadata.model_version` - nested field in user data
* `task_result_cache.output.confidence` - nested field in task results

***

## Debugging Failed Queries

If your widget shows `computation_status: "failed"`, check:

1. **Column names**: Ensure columns exist in your evaluation data
2. **Source specification**: Verify correct source ("data" vs "task\_result\_cache")
3. **GROUP BY alignment**: All non-aggregated `SELECT` columns must be in `groupBy`
4. **Operator/value types**: Match operator to value type (IN requires list, LIKE requires string)
5. **Required params**: PERCENTILE needs percentile param, PERCENTAGE needs percentage\_filters

Check the `error_message` field in the widget result for specific error details.

***

## Next Steps

* Apply these query patterns in the [Widget Types reference](./widget-types/overview)
* See [Getting Started](./getting-started) for end-to-end examples
* Explore [API Reference](/reference/v5/evaluation-dashboards) for programmatic query creation
