> Synerise Documentation — IQL > > This file contains the complete "IQL" section of the Synerise documentation. Each article begins with a top-level "# " heading. The manifest listing all sections is at https://hub.synerise.com/llms-full.txt # Filters The simplest possible IQL query consists of a single item filter. The filter returns true (matched) or false (not matched). ## Elements of a filter An item filter has three elements: - A variable, which is an item attribute based on which you are filtering. - An operator which defines how the attribute's value is compared with the filter value. - A filter value to compare the attribute with. This value can be a constant or inserted dynamically from a [context](/developers/iql/context).
size     ==     10
      ^        ^      ^
  variable  operator  filterValue
In POST request to APIs, the quotation marks around the filterValue must be escaped, for example:
{
    "filter": "color == \"red\"",
    ...
}
## Data sources for filters An item feed is the source for searches and recommendations. The feed is generated from a catalog in Synerise or an external XML source. An item feed is indexed for the purpose of search and recommendation queries. In certain situations, the two indexes work differently. Those situations are described in this guide.
The indexes are updated periodically. An item that was recently added to the item feed is not immediately available in search/recommendation queries.
To learn more about configuring the item feed, see [AI Engine Configuration](/docs/settings/configuration/ai-engine-configuration). ## Item attributes An attribute name is used as a variable, and its value is compared to a filter value. For example, the following filter is true when an item's `brand` attribute is `abcd`: ```plaintext brand == "abcd" ``` **Variables are case-sensitive**, but filter values are not. For example, the filter `brand == "ABCD"` is the same as `brand == "abcd"`, but `Brand == "abcd"` filters only by an attribute named `Brand`, not `brand`.
- In search requests, items can be filtered only by attributes which were defined as filterable when [configuring the search index](/docs/ai-hub/ai-search/define-attributes#filterable-attributes). - In recommendation requests, items can be filtered only by attributes which were defined as filterable when [configuring the AI model](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations).
Attributes with the following data type can be set as filterable: | type | example(s) | | --- | --- | | string | `"foo"` | | boolean | `true`;`false` | | numeric | `12`; `12.34` | | attributes in nested objects | `{"object":{"attr1":"value1","attr2":"value2"}}` | | array of strings, numerics

Arrays must be type-consistent. If different data types (for example, strings and numbers) are included in one array, a filter may not work correctly.| `["foo","bar"]`
`[12,45]`
`[12.34,53.18]` | ### Example items For the purpose of filter examples in this section, the following items are used:
[
    {
        "itemId": "s1",
        "brand": "Abcd",
        "size": {
            "width": 10,
            "height": 20
        },
        "available": true,
        "tags": ["New", "Winter sale"]
        "promoted": "T",
        "price": {
            "value": 129.99
        },
        "winterPromotion": true,
        "category": "X > Y > Z",
        "additionalCategories": ["hiking", "warm", "L > M > N"]
    },
    {
        "itemId": "m1",
        "brand": "Efgh",
        "size": {
            "width": 5,
            "height": 17
        },
        "available": true,
        "tags": ["Winter sale"],
        "price": {
            "value": 249.99
        },
        "category": "X > Y > V"
    }
]
### Top level attributes In order to access an attribute from the root level of the item's object, use the following syntax: ```plaintext attributeName == filterValue ``` For example, `brand == "Abcd"` ### Nested attributes To access a nested value, use dot notation: ```plaintext objectName.attributeName == filterValue ``` For example, `size.width == 5` ### Indexing attributes in arrays (recommendations only) When attributes are nested in arrays or arrays of objects, there is a difference in their indexing for the purposes of recommendation filters: - all values of a textual attribute are indexed - only the first value of a numeric attribute is indexed
This logic does **not** affect [context](/developers/iql/context#item-context) items. Context items are taken from the item feed, not the index.
**Example 1**: Consider the following item:
{
    "itemId": "s1",
    "tags": ["New", "Winter sale"],
    "sizes": [10, 15]
  }
- The `tags` variable contains the `New` and `Winter sale` values. - The `sizes` variable is `10`, because only the first number in an array is indexed. **Example 2**: Consider the following item:
{
    "itemId": "s1",
    "entries": [
        {
            "brand": "Abcd",
            "size": {
                "width": 10,
                "height": 20
            }
        },
        {
            "brand": "Xyz",
            "size": {
                "width": 15,
                "height": 25
            }
        }
    ]
  }
- The `entries.brand` variable contains the `Abcd` and `Xyz` values. - The `entries.size.width` variable is `10`, because it's the width defined in the first object of an array of objects which contain the numerical `width` attribute. ### Category `category` is a special type of attribute that describes a hierarchical structure. It is saved in the following format: ```plaintext "X > Y > Z" ``` where X is the *top level category* and Z is a *leaf level category*. To filter items by category, use the following syntax: ```plaintext category == CATEGORY("X > Y > Z", 0) ``` The above example finds items which are in the `"X > Y > Z"` category or its subcategories. For an explanation of the `0` argument and advanced operations on categories, see [the category function](/developers/iql/functions#category-function). #### Additional categories An item sometimes has a main *category* and a couple of additional categories to which it belongs, saved in the `additionalCategories` array. When the system creates a `category` filter, it combines the values from `category` (string) and `additionalCategories` (array of strings), hiding that complexity from the user. However, these categories are **not** combined in a [context](/developers/iql/context) item. If you want to use the context's additional categories in a filter, you must refer to them explicitly. For example, the following filter checks an item's category against the context's category and additional categories: ```plaintext (category == CATEGORY(context.category, 0)) OR (category == CATEGORY(context.additionalCategories, 0)) ``` ### Metrics In IQL, you can use some pre-defined metrics which exist in all workspaces. Metrics are considered item attributes. The following example checks if the value of a metric for the tested item is more than 10. ```plaintext extra.metrics.9 > 10 ``` The following metrics are available: | Metric | Attribute name | | --- | --- | | Number of page visits in last 7 days | `extra.metrics.9` | | Number of page visits in last 30 days | `extra.metrics.3` | | Number of item purchases yesterday | `extra.metrics.6` | | Number of item purchases in last 7 days | `extra.metrics.10` | | Number of item purchases in last 30 days | `extra.metrics.1` | | Number of item purchases on the same day last week | `extra.metrics.7` | | Total value of item sales in last 30 days, with tax | `extra.metrics.2` | ## Operators Operators are used to define the condition between the value of an attribute and the value to filter by. ### Filtering against strings Filter values are **not** case-sensitive. For example, `brand == "abcd"` is the same as `brand == "ABCD"`. #### equals The `==` operator checks if the strings are identical. ```plaintext brand == "Abcd" ``` #### not equals The `!=` operator checks if the strings are not identical. ```plaintext brand != "Abcd" ``` ### Filtering against numbers #### value comparisons The `<`, `<=`, `==`, `>=`, `>` operators compare the numbers. ```plaintext size.width >= 10 ``` #### value in range The `FROM / TO` operator checks if a variable value is in a range between two values, including those values. ```plaintext size.width FROM 6 TO 15 ```
An alternative way to build this filter is to [use the AND operator](/developers/iql/logic#and): ```plaintext size.width >= 6 AND size.width <= 15 ```
### Filtering against arrays #### value in array **Example 1:** Checking if an item's attribute value exists in an array: ```plaintext brand IN ["Abcd", "Efgh"] ```
An alternative way to build this filter is to [use the OR operator](/developers/iql/logic#or): ```plaintext brand == "Abcd" OR brand == "Efgh" ```
**Example 2:** Checking if a value exists in an array, where the array is an item's attribute (`tags`): The `IN` operator checks if a filter value is included in an array-type attribute's value. ```plaintext "New" IN tags ``` The filter value can only be a string. Note that in this case, the filter value is to the left of the operator, and the variable (item attribute) is on the right. #### array has value The `HAS` operator checks if an array includes a variable (this is an alternative to the `IN` operator). ```plaintext [9, 15] HAS size.width ```
An alternative way to build this filter is to [use the OR operator](/developers/iql/logic#or): ```plaintext size.width == 9 OR size.width == 15 ```
#### value not in array You can filter by checking if the value of a variable is NOT in an array. ```plaintext brand NOT IN ["Abcd", "Efgh"] ```
This filter isn't available in AI Search. Instead, you can use the ['NOT' operator](/developers/iql/logic#not) with the ['IN' filter](#value-in-array), for example: ```plaintext NOT brand IN ["Abcd", "Efgh"] ```
### Filtering against booleans #### equals The `==` operator checks if boolean values are identical. ```plaintext available == true ``` #### not equals The `!=` operator checks if boolean values are not identical. ```plaintext available != true ``` ## What happens if an attribute does not exist in the item? If an attribute does not exist in the item, its value is `null`. #### Check if an attribute exists The `IS DEFINED` operator allows you to check if an attribute exists and has a non-null value. ```plaintext winterPromotion IS DEFINED ``` # Context Some recommendation and search requests allow you to use a context whose attributes will be used when building a filter. For example, you can recommend items in context of an item or items currently in the basket; or in context of the profile which created the basket. This allows you to build dynamic filters instead of using hardcoded values, resulting increased personalization of your recommendations. ## Item context In the following example, the `brand` attribute of a context item is used to filter the results of a request to items which have the same brand: ```plaintext brand == context.brand ``` If the value of the context item's `brand` is `abcd`, the result is the following filter: ```plaintext brand == "abcd" ```
If the context consists of multiple items, the value of that context's is an array of values from all the context items.
**Example:** In the following example, the filter matches items whose `brand` attribute is in the array of context item brands: ```plaintext brand IN context.brand ``` If the context items' brands are `abcd` and `efgh`, the result is the following filter: ```plaintext brand IN ["abcd","efgh"] ``` **Example:** In the following example, the filter matches items whose `price.value` attribute is higher than the [average](/developers/iql/functions#numeric-functions) `price.value` attribute of multiple context items: ```plaintext price.value > AVG(context.price.value) ``` If the context items' prices are 10.49, 1.99, and 62.99, the result is the following filter: ```plaintext price.value > AVG([10.49, 1.99, 62.99]) ```
The item context is taken from the item catalog instead of the index. Because of this: - attributes do **not** need to be configured as filterable to be used as context. - the context's array-type attributes are **not** affected by the behavior described in ["Indexing attributes in arrays"](/developers/iql/filters#indexing-attributes-in-arrays-recommendations-only).
## Profile context When the context is a profile, you can use attributes, tags, segmentations, expressions, and aggregates as filter values. ### Limits In one request, you can use: - up to 20 profile attributes - 1 segmentation - 2 aggregates OR 2 expressions OR 1 expression and 1 aggregate The limits apply to unique elements. For example, you can refer to the same segmentation a few times, but you can't include 2 different segmentations.
- If the request refers to a campaign (for example, in the ["Get recommendations by campaign" endpoint](https://hub.synerise.com/api-reference/ai-recommendations#operation/GetRecommendationsByCampaignV2)), the campaign's filters and the additional filters share the limit. - If the request uses boosting strategies (for example, in the ["Scoring be metric" endpoint](https://hub.synerise.com/api-reference/ai-recommendations#operation/PostRecommendLastViewedForUserItems)), the boosting strategies and the filters share the limit.
### Profile attributes In the following example, the brand of the item must be the same as the profile's `favoriteBrand` attribute: ```plaintext brand == client.attributes.favoriteBrand ``` If the `favoriteBrand` attribute has the value `"abcd"`, the result is the following filter: ```plaintext brand == "abcd" ``` If the attribute doesn't exist in the profile, the filter is ignored. ### Profile tags In the following example, the tag `"vip"` must exist in the profile's tags: ```plaintext "tag" IN client.tags ``` **Example:** A profile has the `"vip"` tag. When you create the following [IF statement](/developers/iql/logic#if): ```plaintext IF("vip" IN client.tags, discount > 0, discount == 0) ``` it evaluates to: ```plaintext discount > 0 ``` ### Profile segmentations You can check if a profile belongs to a [segmentation](/docs/analytics/segmentations). The segmentation is identified by its UUID and calculated at the time of the request. ```plaintext client.segmentations HAS ``` **Example:** A profile belongs to segmentation `39d39ad1-6d7b-4401-b067-998bf7d56d9f`. When you create the following [IF statement](/developers/iql/logic#if): ```plaintext IF(client.segmentations HAS "39d39ad1-6d7b-4401-b067-998bf7d56d9f", discount > 0, discount == 0) ``` it evaluates to: ```plaintext discount > 0 ``` ### Profile expressions You can access the result of an [expression](/docs/crm/expressions) calculated for the context profile. The expression is identified by UUID and calculated at the time of the request. ```plaintext client.expressions.uuid ``` **Example:** Expression `0abc195a-548e-460d-a904-1e285b8adb96` returns `15.0` for the context profile. If you create the following filter: ```plaintext discount > client.expressions.0abc195a-548e-460d-a904-1e285b8adb96 ``` it evaluates to: ```plaintext discount > 15.0 ``` If the expression does not exist, its value in the filter is `null`. ### Profile aggregates You can access the result of an [aggregate](/docs/crm/aggregates) calculated for the context profile. The aggregate is identified by UUID and calculated at the time of the request. ```plaintext client.aggregates.uuid ``` If the aggregate returns a list, run it through the [TO_ARRAY filter](/developers/iql/functions#to_array). **Example:** Aggregate `08dfe176-2a37-3234-bf4f-3fa9b3b309bc` returns `180.0` for the context profile. If you create the following filter: ```plaintext price.value < client.aggregates.08dfe176-2a37-3234-bf4f-3fa9b3b309bc ``` it evaluates to: ```plaintext price.value < 180.0 ``` If the aggregate does not exist, its value in the filter is `null`. ## What happens if an attribute does not exist in the context? If an attribute does not exist in the context, its value becomes `null == true` and the filter which uses it becomes unprocessable. If that filter is part of a larger expression, it is ignored. **Example 1:** The following filter matches NO ITEMS: ```plaintext discount == context.thisAttributeDoesNotExist ``` **Example 2:** The following filter matches items whose `discount == 0`, because the other condition is unprocessable. ```plaintext discount == 0 AND discount == context.thisAttributeDoesNotExist ``` ### Check if a value exists The `IS DEFINED` operator allows you to check if an attribute exists and has a non-null value. The following filter uses an [IF statement](/developers/iql/logic#if) to check if an attribute exists and act accordingly: ```plaintext IF(context.thisAttributeDoesNotExist IS DEFINED, discount > 0, discount == 0) ``` The context attribute does not exist, so the `discount == 0` filter is applied. # Functions Functions allow you to perform some additional operations when building the IQL query string. You can use functions inside functions, for example: ```plaintext effectivePrice.value <= MULTIPLY(MIN(context.effectivePrice.value), 1.2) ``` In the above example: 1. `(MIN(context.effectivePrice.value)` gets the lowest value of an attribute from the context items. 2. `MULTIPLY(...), 1.2` multiplies that lowest value by `1.2`. 3. The resulting filter matches items whose `effectivePrice.value` is at least 20% higher than in the cheapest context item. ## CATEGORY {#category-function} The `CATEGORY` function allows you to: - access categories from the context - access context attributes that are formatted as categories, but not named `category` (for example, a custom `favoriteCategory` attribute in a profile) - manipulate category levels The function takes two arguments: - the source of the category value - how many category levels you want to drop or include (`0` does not drop any levels). Positive numbers **drop** levels from the bottom, negative numbers **include** from the top. **Example 1**: Accessing category from the item context and dropping one level from the bottom (right): ```plaintext category == CATEGORY(context.category, 1) ``` If the context category is `X > Y > Z` the result of the function is the following filter: ```plaintext category == "X > Y" ``` **Example 2**: Accessing category from the item context including two levels from the top (left): ```plaintext category == CATEGORY(context.category, -1) ``` If the context category is `X > Y > Z` the result of the function is the following filter: ```plaintext category == "X" ``` **Example 3**: Adding an [OR statement](/developers/iql/logic#or) and the `additionalCategories` attribute, no levels dropped: ```plaintext category == CATEGORY(context.category, 0) OR category == CATEGORY(context.additionalCategories, 0) ``` **Example 4**: Accessing a category saved as a custom profile attribute `"favoriteCategory": "foo > bar"`: ```plaintext category == CATEGORY(client.attributes.favoriteCategory, 0) ``` The resulting filter is: ```plaintext category == "foo > bar" ``` ## Check if value is null The `IS DEFINED` operator allows you to check if an attribute exists and has a non-null value. For example, the following filter matches items in which `winterPromotion` has a non-null value: ```plaintext winterPromotion IS DEFINED ``` You can also check contexts: ```plaintext IF(context.thisAttributeDoesNotExist IS DEFINED, discount > 0, discount == 0) ``` ## TO_ARRAY If your filters use an aggregate that returns a list of values, you must run the result of that aggregate through the `TO_ARRAY` function. This is because Synerise aggregates return arrays as strings: `"["foo","bar"]"` ```plaintext brand IN TO_ARRAY(client.aggregates.35bb6e95-443a-3303-af07-cacbb063acfe) ``` ## REQUIRED Returns an error instead of null when a profile context is unavailable. Recommendations in the affected slot are not displayed at all. You can use this to make sure that recommendations are only displayed when the context is available. Can be used with these context elements: - aggregates Example: `brand IN TO_ARRAY(REQUIRED(client.aggregates.17c9339d-c938-4059-9bfc-f990d64d3501))` - expressions Example: `price.value > REQUIRED(client.expressions.UUID)` - segmentations ```IF(REQUIRED(client.segmentations) HAS "8c1b3540-2a7f-11ec-8d3d-0242ac130003", flag == "premium", flag == "regular")``` - profile attribute Example: `brand == REQUIRED(client.attributes.favouriteBrand)` - profile tags Example: `tag IN REQUIRED(client.tags)` ## Numeric functions You can perform mathematical operations on item context and profile context attributes. ### MIN Returns the lowest value from an array. ```plaintext attributeName >= MIN([]) ``` **Example**: In the following example, the context is a few items with a `size.width` attribute: ```plaintext size.width >= MIN(context.size.width) ``` The resulting filter is: ```plaintext size.width >= MIN([10.0,14.0,20.0]) ``` which calculates into: ```plaintext size.width >= 10.0 ``` ### MAX Returns the highest value from an array. ```plaintext attributeName >= MAX([]) ``` **Example**: In the following example, the context is a few items with a `size.width` attribute: ```plaintext size.width >= MAX(context.size.width) ``` The resulting filter is: ```plaintext size.width >= MAX([10.0,14.0,20.0]) ``` which calculates into: ```plaintext size.width >= 20.0 ``` ### AVG Returns the average value of an array. ```plaintext attributeName >= AVG([]) ``` **Example**: In the following example, the context is 3 items with a `size.width` attribute: ```plaintext size.width >= AVG(context.size.width) ``` The resulting filter is: ```plaintext size.width >= AVG([10.0,14.0,20.0]) ``` which calculates into: ```plaintext size.width >= 14.666666666666666 ``` ### SUM Returns the sum of all elements in an array. All elements must be static numbers or a context that returns an array of numbers. ```plaintext attributeName == SUM([]) ``` In the following example, the context is 3 items with a `regularPrice` attribute. ```plaintext price > SUM(context.regularPrice) ``` The resulting filter is: ```plaintext price > SUM([10.0,15.65,14.30]) ``` which calculates into: ```plaintext price > 39.95 ``` ### ADD Adds one value to one other value. If you want to add more values at once, use [`SUM`](#sum). Only one of the arguments can be a value from a context (item or profile context), the other must be a static number. ```plaintext attributeName == ADD(value,number) ``` **Example 1**: In the following example, the context is one item with `"size": 10`: ```plaintext size > ADD(context.size,5) ``` The resulting filter is: ```plaintext size > ADD(10.0,5.0) ``` which evaluates to: ```plaintext size > 15 ``` ### MULTIPLY Multiplies values. The first argument is a context attribute or a number, the second attribute is a number. ```plaintext attributeName == MULTIPLY(value,number) ``` **Example**: In the following example, the context is one item with `"price.value": 5`: ```plaintext price.value > MULTIPLY(context.price.value,0.7) ``` The resulting filter is: ```plaintext price.value > MULTIPLY(5.0,0.7) ``` which evaluates to: ```plaintext price.value > 3.5 ``` ## TOP/BOTTOM values The `TOP_K` and `BOTTOM_K` functions let you retrieve a number of items with the top/bottom values of an attribute. You can add a filter to the items. **Syntax**: ```plaintext TOP_K(value, attribute, filter) BOTTOM_K(value, attribute, filter) ``` where: - `value` is the number of items to retrieve - `attribute` is the tested attribute - `filter` is a filter string **Example 1:** Retrieve 10 items with the lowest prices: ```plaintext BOTTOM_K(10, price.value , ALL) ``` **Example 2:** Retrieve 10 red items with the highest prices: ```plaintext TOP_K(10, price.value , color == red) ``` **Example 3:** Retrieve 10 available items with the highest [value of a metric](/developers/iql/filters#metrics): ```plaintext TOP_K(10, extra.metrics.9 , availability == true) ``` ## Time functions These functions let you use dates and times in a filter. ### TIMESTAMP Converts a date-time string or a timestamp (string) into a timestamp (integer). **Syntax**: ```plaintext TIMESTAMP(string) ``` where `string` can be: - an ISO 8601 date-time string, for example `2024-01-01T10:00:00Z` If the string doesn't declare a timezone, the timezone of the workspace is applied. `Z` declares UTC as the timezone. - a timestamp in seconds as a string, for example `1727337789` The result is a timestamp as an integer, in seconds. ### NOW Gets current time as a timestamp (integer) in seconds. **Syntax**: ```plaintext NOW() ``` The function doesn't have any arguments. ### DATE_ADD Adds or subtracts from a date-time (string). **Syntax**: ```plaintext DATE_ADD(unit, number, time) ``` where: - `unit` is one of: `minutes`, `hours`, `days`, `months`, `years` This argument is NOT case-sensitive. `months` takes into account the different number of days each month and `years` handles leap years. - `number` is the value to add. Negative values result in subtraction. - `time` is an ISO 8601 date-time string, a timestamp in seconds (as string or integer), or the `NOW()` function. If date-time doesn't declare a timezone, the timezone of the workspace is applied. `Z` declares UTC as the timezone. **Examples**: - Add 31 days to a fixed date: ``` DATE_ADD("days", 31, "2024-01-01T10:00:00Z") ``` ``` DATE_ADD("days", 31, "1704099600") ``` ``` DATE_ADD("days", 31, 1704099600) ``` - Subtract 3 months from current time: ``` DATE_ADD("MONTHS", -3, NOW()) ``` ## ALL/NONE This special function lets include or exclude all items from the results. - `ALL` - take all items - `NONE` - take no items This is especially useful in the [IF statement](/developers/iql/logic#if). ``` # Logical operators You can combine filter expressions by using conditionals. This allows you to build powerful filtering logic. ## AND `AND` is the conjunction operator. The following filter returns items which meet two conditions: the brand is `"abcd"` and the price is 10 or more. ```plaintext brand == "abcd" AND price.value >= 10 ``` ## OR `OR` is the alternative operator. The following filter returns items which meet at least one of the conditions: - brand is `"abcd"` - the price is 10 or more ```plaintext brand == "abcd" OR price.value >= 10 ``` If both conditions are met, the filter also matches the items (and/or logic). ## NOT `NOT` is the negation operator. The following filter returns items whose brand is not `"abcd"`: ```plaintext NOT(brand == "abcd") ``` ## IF If you want to add conditional logic to the filter, you can use the `IF` statement. ```plaintext IF(predicate, thenFilter, elseFilter) ``` where: - `predicate` is a logical expression in which you can use the context, but you cannot use properties of the item that is being tested against the filter. - `thenFilter` - is returned if the predicate is true. - `elseFilter` - is returned if the predicate is false. ### Examples **Example 1**: A basic IF statement: ```plaintext IF(context.brand == "abcd", brand == "abcd" , brand != "abcd") ``` - If the context item's brand is `"abcd"`, the resulting item filter is `brand == "abcd"` (items from the same brand as the context match the filter). - Otherwise, the filter is `brand != "abcd"` (items from all other brands match the filter). **Example 2**: IF statement with a reference to a segmentation and the [`ALL/NONE`](/developers/iql/functions#allnone) function: ```plaintext IF(client.segmentations HAS "39d39ad1-6d7b-4401-b067-998bf7d56d9f", price.value > 100, ALL) ``` If the context profile belongs to the `39d39ad1-6d7b-4401-b067-998bf7d56d9f` segmentation, the resulting item filter is `price.value > 100`. Otherwise, the filter matches all items in the database. **Example 3**: IF statement nested in another IF statement: ```plaintext IF("NewCustomer" IN client.tags, price.value > 100, IF(context.brand == "abcd", price.value <= 100, ALL)) ``` - If the context profile's tags include `"NewCustomer"`, the item filter is `price.value > 100`. Otherwise, the nested IF statement is evaluated. - In the nested IF statement, if the context item's brand is `abcd`, the filter is `price.value <= 100`. Otherwise, the filter matches all items in the database. **Example 4**: IF statement with the `AND` logical operator in the predicate: ```plaintext IF("NewCustomer" IN client.tags AND context.brand == "abcd", price.value > 100, price.value <= 100) ``` If the context profile has the tag `NewCustomer` and the context item's brand is `abcd`, the filter matches items whose price is more than 100. ## Grouping expressions The parentheses `()` allow you to group conditions in order to create more complex and nested expressions. **Example**: ```plaintext (brand == "abcd" AND price.value >= 10) OR brand == "efgh" ``` The filter returns items which meet at least one of the following conditions: - brand is `"abcd"` while the price is 10 or more (both conditions must be met). - brand is `"efgh"`. # Validate and test IQL A validation endpoint is available for: - testing if the syntax of your IQL query is correct. - previewing the results of the IQL (function results, actual values of context attributes). - checking examples of items which match the IQL query. - checking if a particular item matches the IQL query.
This article presents one request example. For a complete list of all available options and response parameters, see the [API reference](https://hub.synerise.com/api-reference/ai-suite#operation/ValidateItemFilter).
## Request
curl --location --request POST 'https://api.synerise.com/items/v2/filter/validate?itemsCatalogId=default' \
--header 'authorization: Bearer eyJhbG...66Wr4' \
--header 'Content-Type: application/json' \
--data-raw '{
    "filteringString": "IF(\"vip\" IN client.tags, discount > context.discount, discount == 0)",
    "contextItems": ["549"],
    "candidateItems": ["302","413"],
    "clientUUID": "516e431d-c6d9-488e-b184-f8b15f93baeb"
}'
where - `itemsCatalogId=default` is the ID of the item feed which is the source for items tested by the query - `filteringString` is the complete IQL query (note the escaped quotes in the query) - `contextItems` is an array of context items, in this case it's one item - `candidateItems` is an array of items to test against the `filteringString` - `clientUUID` is the identifier of the context profile ## Response
{
    "filteringString": "IF(\"vip\" IN client.tags, discount > context.discount, discount == 0)",
    "contextItems": [
        "549"
    ],
    "clientUUID": "516e431d-c6d9-488e-b184-f8b15f93baeb",
    // informs if the IQL syntax (and only the syntax) is valid:
    "parserResult": {
        // processed filtering string:
        "parsedFilteringString": "IF(\"vip\" IN client.tags THEN discount > context.discount ELSE discount == 0.0)",
        "valid": true
    },
    // summary of context values used in the query. Details are available in the API reference.
    "extracts": {
        "clientExtracts": {
            "aggregateConstants": [],
            "attributeConstants": [],
            "expressionConstants": [],
            "segmentationsConstant": [],
            "tagsConstant": true
        },
        "contextConstants": [
            "discount"
        ],
        "variables": [
            "discount"
        ]
    },
    // results of running the query in context of the item feed and its configuration:
    "evaluationResult": {
        "evaluationErrors": [],
        // fully processed filtering string, with inserted values of context attributes:
        "modifiedFilteringString": "IF(\"vip\" IN [documentation,test,example] THEN discount > 0.0 ELSE discount == 0.0)",
        // the number of matching items:
        "resultsSize": 584
    },
    // results of checking particular items against the filter:
    "candidateItems": [
        {
            "itemId": "302",
            "valid": false
        },
        {
            "itemId": "413",
            "valid": true
        }
    ],
    // an array of example items which matched the filter:
    "exampleItems": [
        "100",
        "356",
        "257",
        "377",
        "358",
        "297",
        "136",
        "514",
        "196",
        "404"
    ]
}
# Items Query Language (IQL) Items Query Language (IQL) is a language which allows you to build item filters for your search and recommendation requests.
This guide describes how to build query strings used in SDK and API calls. If you want to learn about building the same filters by using the Synerise Application's GUI, see the [User Guide](/docs/ai-hub/recommendations-v2/recommendation-filters). - The filters built in the Synerise Applications are embedded in recommendation campaigns. - The filters included in SDK and API calls can replace the campaign's embedded filters or are combined with them.
A query string consists of the following elements: - **Item filters** are the basic blocks which compare an items' attributes with values. - **Context** (optional) is a profile or item(s) whose attributes can be used as the value to compare the attribute with. - **Functions** (optional) manipulate the attribute values. There's also a special ALL/NONE function. - **Logic** (optional) is built with AND/OR/IF statements and the NOT operator.