> For the complete documentation index, see [llms.txt](https://docs.mediarithmics.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/computed-fields.md).

# Computed fields

Turn behavioural and profile data into aggregated values available as ordinary schema fields.

## Your goal

Get an aggregate - sales over the last 90 days, favourite category, an RFM score - available as a normal field on the UserPoint, so queries, segments, and dashboards can use it without recomputing anything.

## Expected outcome

A field declared in your schema whose value is calculated on a schedule, queryable exactly like a collected field.

## What a computed field is

A **computed field** is a dynamic field defined in the schema, linked to a script that is triggered for each new user activity or profile update and that performs a computation of a function's result **on a regular basis**.

A **Computed Field Function** is the [plugin](/setup-and-monitor/extend-the-platform/plugin-architecture.md) behind it - of type `COMPUTED_FIELD_FUNCTION`. The computed field itself is an instance of that function applied in a specific context, and it must be declared in your schema to be usable.

Computed fields are always defined at the **UserPoint** level.

### The four elements that define one

| Element              | What it is                                                                |
| -------------------- | ------------------------------------------------------------------------- |
| **Input data**       | One or more sources: activity data, profile data, or both.                |
| **Formula**          | The logic - a sum, a count, or a more complex operation.                  |
| **Lookback window**  | The historical depth to analyse.                                          |
| **Update frequency** | How often the result is recomputed - typically daily, weekly, or monthly. |

<details>

<summary>Two worked definitions</summary>

**Sales generated on smartphones over the last 3 months**

* Input data: purchase data filtered on "smartphone" products
* Formula: sum of the sales figures for each sale
* Lookback window: 90 days
* Update frequency: daily

**Favourite type of content**

* Input data: page views
* Formula: sum of page views per category - the category field to use has to be defined - and the category with the highest score is saved as the favourite
* Lookback window: 12 months
* Update frequency: monthly

</details>

### The three moving parts inside one

| Part       | What it holds                                                                                                                                              |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **State**  | The data stored to build the result - the history. Each new activity updates the state, which is why the state is closely tied to the lookback window.     |
| **Logic**  | Simple, like a formula, a sum, or a count; or more complex, like a logical operation.                                                                      |
| **Result** | The data calculated and stored - the score or scores you use. A single variable or an object, depending on the computation. It is computed from the state. |

## When to use one, and when not to

{% tabs %}
{% tab title="Use a computed field" %}
Use one when the outcome cannot be achieved with existing schema directives, or to simplify a query by replacing several directives with a single field. Because the value is precomputed, queries using it are faster.

Handled well by computed fields:

* Retrieve the most recent event - last visit, last transaction.
* Get the total amount for a type of event - sum of transactions in the last 30 days, total spend on a product category.
* A weighted sum, such as an affinity total.
* Compare several channels, for instance to find the best channel for transactions.

Common business uses: developing customer understanding (whether someone buys online, offline, or both), making segmentation easier (an RFM score), optimising personalisation (appetite for discounts), and enhancing measurement (sales over the past 30 days, to measure a campaign's impact).
{% endtab %}

{% tab title="Use a standard directive" %}
A standard directive is enough when you only need to filter, for example: get all users with at least a specific amount for one category.

Adding a computed field for something a directive already does adds a moving part for no gain.
{% endtab %}

{% tab title="Not possible" %}
Identifying the top X% of a group - the top 10% of buyers, say - is **not** something a computed field can do.

Computed fields are designed to compute data at the level of a single user. Comparing one user's result against the rest of the datamart requires specific development, and feasibility can only be assessed case by case.
{% endtab %}
{% endtabs %}

## What it changes in your queries

The same use case - users who spent more than €100 on IT products in the last three months - expressed both ways:

{% tabs %}
{% tab title="With standard directives" %}

```sql
SELECT { id } FROM UserPoint
WHERE activity_events @ScoreSum(min : 100) {
    basket {
        items @ScoreField(name:"price") @ScoreSum(result:"score_value") {
            category="IT" AND date >= "now-3M/M"
        }
    }
}
```

The sum is computed while the query runs.
{% endtab %}

{% tab title="With a computed field" %}

```sql
SELECT { id } FROM UserPoint WHERE IT_amount_3months >= 100
```

The field is calculated on a regular basis, so no computation happens during query execution. Response times are faster because the value is precomputed and readily available.
{% endtab %}
{% endtabs %}

Once live, a computed field behaves like a regular field - it is transparent to the person querying it.

## Lifecycle

```mermaid
stateDiagram-v2
    [*] --> INITIAL: instance created
    INITIAL --> INITIAL_LOADING: declared in the schema and validated
    INITIAL_LOADING --> ACTIVE: loading job completed successfully
```

1. **`INITIAL`** - the instance is created with this status.
2. **`INITIAL_LOADING`** - once declared in the schema and successfully validated, an initial loading job is triggered.
3. **`ACTIVE`** - the computed field becomes active if the job completes successfully.

Technically: the field is declared in the schema, the state is updated by new user activities or profile updates, the result is computed from the current state, and the result is stored for querying.

## Set one up

{% hint style="info" %}
Computed fields are created as plugins, which requires collaboration with the mediarithmics Professional Services team: defining the logic, writing the plugin specification, developing the plugin, and configuring the computed field. Users are not autonomous in creating them today - discuss your needs with your account manager.
{% endhint %}

The project runs in four stages: **framing** (which fields to calculate, the methodology, the update frequency), **writing the plugin specification**, **developing the plugin**, and **configuring the computed fields** including schema indexing and production testing.

{% hint style="warning" %}
Framing is the stage that decides whether the rest goes quickly. Come to it with a clear use case and a clear idea of the data behind it.
{% endhint %}

{% stepper %}
{% step %}

### Create the Computed Field Function

A plugin of type `COMPUTED_FIELD_FUNCTION`, created through the API following the standard plugin process, or through the Computing Console interface. See [Build a computed field](/setup-and-monitor/extend-the-platform/build-a-computed-field.md).
{% endstep %}

{% step %}

### Create the computed field in the platform

In **Navigator > Settings > Datamart**, open **Computed Fields** and add a new one. Select the plugin and the version of the instance to use, then complete:

| Field                        | What it sets                                                                  |
| ---------------------------- | ----------------------------------------------------------------------------- |
| **Name**                     | The name of the computed field.                                               |
| **Description**              | Optional.                                                                     |
| **Technical name**           | The name used to reference the field in the schema.                           |
| **Compute period (in days)** | The maximum duration before the periodic update of the result.                |
| **Events filter**            | A GraphQL selector query filtering the activities that trigger state updates. |
| {% endstep %}                |                                                                               |

{% step %}

### Declare it in your schema

Use the `@ComputedField` directive at the right level, with a technical name matching the one used at creation:

```graphql
type UserPoint {
  id: ID!
  accounts: [UserAccount]
  rfm_score: RfmScore @ComputedField(technical_name: "RfmScore") @TreeIndex(index:"USER_INDEX")
}

type RfmScore {
  # ...
}
```

Saving triggers a schema validation, which checks that your datamart has access to every declared computed field and verifies their integration with the schema.

{% hint style="warning" %}
The computed field must be on the `UserPoint` object.
{% endhint %}
{% endstep %}

{% step %}

### Wait for the initial loading

Once the schema is validated, a job initialises the field so that its state matches the current timeline. For every UserPoint in the datamart, the timeline is processed and the update functions are executed.

Monitor it in **Computing Console > Computed Fields**, where you can see whether the field is ready or still loading.

This can take **up to 72 hours**, because it computes the timelines of all UserPoints.

{% hint style="danger" %}
Do not use the computed field until the initial loading is complete. Queries will not return an error, but the result may be inaccurate.
{% endhint %}
{% endstep %}

{% step %}

### Use it

Like any other field:

```sql
SELECT { rfm_score } FROM UserPoint
```

And if it is indexed:

```sql
SELECT { id } FROM UserPoint WHERE rfm_score = "PASSIVE"
```

{% endstep %}
{% endstepper %}

## Boundaries

| Question                                                  | Answer                                                                                                                                                                                            |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Can it be computed per profile rather than per UserPoint? | Yes - for each computed field you choose whether it is computed at the UserPoint mesh (possibly with several linked profiles) or at the profile mesh.                                             |
| Can it live anywhere in the schema?                       | No. A computed field is always defined at the root of the schema, on the `UserPoint`.                                                                                                             |
| Can one computed field feed another?                      | Not in the Alpha version, because the order in which computed fields are calculated cannot be controlled.                                                                                         |
| Can it use statistics over the whole datamart?            | Not by design - computed fields compute data at a single-user level. A comparison against the rest of the datamart may sometimes be possible through specific development, assessed case by case. |
| Can I create one myself?                                  | Not currently. The Professional Services team is involved in the project.                                                                                                                         |

{% hint style="danger" %}
The `State` size is restricted to a maximum of **1 MB**. If the limit is exceeded, the update is discarded and not saved.
{% endhint %}

## Verify

* The field appears in the schema and validation passes.
* **Computing Console > Computed Fields** reports the initial loading as finished.
* `SELECT { your_field } FROM UserPoint` returns values.
* If the field is indexed, a `WHERE` query on it returns a plausible population.

## Related pages

<table data-view="cards" data-search="false"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Build a computed field</strong></td><td>Writing the plugin: methods, state design, tests.</td><td><a href="/setup-and-monitor/extend-the-platform/build-a-computed-field.md">Build a computed field</a></td></tr><tr><td><strong>Schema definition</strong></td><td>Where the <code>@ComputedField</code> directive is declared.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/schema-definition.md">Schema definition</a></td></tr><tr><td><strong>Affinity &#x26; Intention</strong></td><td>The other ways to add calculated data to the graph.</td><td><a href="/setup-and-monitor/plan-and-integrate/set-up-advanced-features/affinity-and-intention-ml-algorithm.md">Affinity &amp; Intention</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/computed-fields.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
