Query objects
This topic describes how to build a JSON object to create a behavioral query in Optimizely Personalization.
Query objects
A behavioral query describes how a single customer's events can be converted into a meaningful value. Each query is specified using a JSON object. The Use Cases topic describes how you can evaluate these queries. The format of these query objects is documented in the following topic.
Each "step" of query construction creates a new, separate property in the top-level query object.
An empty query object evaluates to the list of all events that have been generated by the current visitor.
// Query for all events.
{
"version": "0.2"
}
// Result:
[
{
"type": "pageview",
"name": "AB_landing_page",
"category": "landing_page",
"tags": {
"theme": "urban_explorer"
},
"session_index": 1,
"time": 1111111111000
},
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 12800,
"product_name": "Scout Backpack"
},
"session_index": 1,
"time": 1111111115000
},
{
"type": "click",
"name": "AB_add_to_cart",
"category": "add_to_cart",
"tags": {
"price": 12800,
"product_name": "Scout Backpack",
"quantity": 1
},
"session_index": 1,
"time": 1111111119000
},
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
}
]
Version
You must include a version number in each of your query objects. This ensures that your query will always be evaluated the same, even if Optimizely Web Experimentation introduces a backwards-incompatibile query format in the future.
// Minimal query object.
{
"version": "0.2"
}
Filter
You can filter the results by passing in an array of filters, each composed of a field, comparator, and value. This narrows down the query to those events that match (all) filters.
You can filter by ["age"] even though age is not an actual event field. This is particularly useful if you want to select events that were generated in the last N
days.
These comparators are usable on all fields:
"eq" | Requires the field value to roughly equal the filter's value. For strings, this is case-insensitive, as well as leading- and trailing-whitespace-insensitive. |
"is" | Requires the field value to exactly equal the filter's value. |
"in" | Requires the field value to be contained in the filter's value, which must be an ["array", "of", "acceptable", "values", "such as", 2, "and", true]. For strings, this is case-insensitive, as well as leading- and trailing-whitespace-insensitive. |
"contains" | Requires the field value, which must be an array, to contain the filter's value according to indexOf. For strings, this is case-insensitive. |
"exists" | Requires the field value to be defined; the filter need not specify a value. This is only useful for tags, since top-level fields are defined for every event. |
The following string comparators can be used on string fields like type, name, and category and also on string tags:
"regex" | Requires the field value to match the filter's value, which must be either a case-insensitive RegExp "pattern", or a ["pattern", "flags"] array. |
The following number comparators can be used on numeric fields like time and age and also on numeric tags like revenue. These comparators automatically reject nonnumeric field values.
"gt" | Requires the field value to be greater than the filter's value, which must be a number. |
"gte" | Requires the field value to be greater than or equal to the filter's value, which must be a number. |
"lt" | Requires the field value to be less than the filter's value, which must be a number. |
"lte" | Requires the field value to be less than or equal to the filter's value, which must be a number. "between": Requires the field value to be in the inclusive interval specified by the filter's value, which must be an array of two numbers. |
If comparator is omitted, it defaults to "eq". The value can only be omitted when you have specified the "exists" comparator.
// Query for click events.
{
"version": "0.2",
"filter": [
{
"field": ["type"],
"value": "click"
}
]
}
// Result:
[
{
"type": "click",
"name": "AB_add_to_cart",
"category": "add_to_cart",
"tags": {
"price": 12800,
"product_name": "Scout Backpack",
"quantity": 1
},
"session_index": 1,
"time": 1111111119000
}
]
// Query for events that demonstrate interest in the "Scout Backpack".
{
"version": "0.2",
"filter": [
{
"field": ["tags", "product_name"],
"value": "Scout Backpack"
}
]
}
// Result:
[
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 12800,
"product_name": "Scout Backpack"
},
"session_index": 1,
"time": 1111111115000
},
{
"type": "click",
"name": "AB_add_to_cart",
"category": "add_to_cart",
"tags": {
"price": 12800,
"product_name": "Scout Backpack",
"quantity": 1
},
"session_index": 1,
"time": 1111111119000
}
]
// Query for events where a price was known and was at least $135.00.
{
"version": "0.2",
"filter": [
{
"field": ["tags", "price"],
"comparator": "gte",
"value": 13500
}
]
}
// Result:
[
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
}
]
// Query for pageview events that happened between 7 and 14 days ago.
{
"version": "0.2",
"filter": [
{
"field": ["type"],
"value": "pageview"
},
{
"field": ["age"],
"comparator": "between",
"value": [7*24*60*60*1000, 14*24*60*60*1000]
}
]
}
// Result:
[
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
}
]
// Query for events that happened in the current session.
{
"version": "0.2",
"filter": [
{
"field": ["session_index"],
"value": 0
}
]
}
// Result:
[
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
}
]
Sort by time
You can sort events by ascending or descending ["time"]
.
// Query for events, sorted from newest to oldest.
{
"version": "0.2",
"sort": [
{
"field": ["time"],
"direction": "descending"
}
]
}
// Result:
[
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
},
...,
{
"type": "pageview",
"name": "AB_landing_page",
"category": "landing_page",
"tags": {
"theme": "urban_explorer"
},
"session_index": 1,
"time": 1111111111000
},
]
Pick
You can pick the values for a single field out of an array of (potentially filtered and sorted) events.
// Query for tag values, sorted from most recent to least recent.
{
"version": "0.2",
"sort": [
{
"field": ["time"],
"direction": "descending"
}
],
"pick": {
"field": ["tags", "product_name"]
}
}
// Result:
[
"Derby Tier Backpack",
"Scout Backpack",
"Scout Backpack"
]
Sort by frequency
If field values are being picked out of events, you can sort those values by ["frequency"]
, either "ascending" or "descending".
This de-duplicates the picked values and sorts them based on how frequently each one was found in the filtered events. This will also override any sort that may have been performed on the underlying events.
Unlike conventional field identifiers, ["frequency"]
does not correspond to a real event field.
// Query for unique tag values sorted from most frequent to least frequent.
{
"version": "0.2",
"pick": {
"field": ["tags", "product_name"]
},
"sort": [
{
"field": ["frequency"],
"direction": "descending"
}
]
}
// Result:
[
"Scout Backpack",
"Derby Tier Backpack"
]
Reduce
You can reduce a list of values into a single value using an aggregator.
These aggregators are usable on all types of values:
"nth" | Reduce the list by choosing the nth value and ignoring the rest. "n" is specified separately and is 0-indexed, so you should specify 0 if you want the first value. This aggregator is only meaningful when values have been sorted. |
"count" | Reduce the list by resolving to the number of values in the list. There's no need to sort or pick when using this aggregator. |
The following mathematical aggregators are usable on numeric fields like time and age and also on numeric tags like revenue:
"sum" | Reduce the list by computing the sum of the numeric values. |
"avg" | Reduce the list by computing the average of the numeric values. |
"max" | Reduce the list by choosing the largest of the numeric values. |
"min" | Reduce the list by choosing the smallest of the numeric values. |
Nonnumeric values are ignored when evaluating a mathematical aggregator, as if those values didn't exist at all. This ensures, for example, that an "avg" computation is not diluted through zero-filling of undefined values. JavaScript numbers like NaN, +Infinity, and -Infinity are still recognized and can severely affect the result of the aggregation.
// Query for the single most recent event.
{
"version": "0.2",
"sort": [
{
"field": ["time"],
"direction": "descending"
}
],
// Reduce a list of sorted events into a single event.
"reduce": {
"aggregator": "nth",
"n": 0
}
}
// Result:
{
"type": "pageview",
"name": "AB_product_page",
"category": "product_detail",
"tags": {
"price": 14700,
"product_name": "Derby Tier Backpack"
},
"session_index": 0,
"time": 2222222222000
}
// Query for the average price across all product page views.
{
"version": "0.2",
"filter": [
{
"field": ["type"],
"value": "pageview"
}
],
"pick": {
"field": ["tags", "price"],
},
// Reduce a list of picked field values into a single value.
"reduce": {
"aggregator": "avg"
}
}
// Result:
13750
Updated almost 2 years ago