Grouping Reference
Refer to the grouping guide for an introduction to Vespa's grouping feature.

Group query results using a custom expression (using the
group
clause): A numerical constant.
 A document attribute.

A function over another expression (
xorbit
,md5
,cat
,xor
,and
,or
,add
,sub
,mul
,div
,mod
) or any other expression.  The data type of an expression is resolved using best effort, similarly to how you expect common programming languages to resolve arithmetics of different data typed operands.

The results of any expression are either scalar or single dimension arrays.
add(<array>)
adds all elements together to produce a scalar.
add(<arrayA>, <arrayB>)
adds each element together producing a new array whose size ismax(<arrayA>, <arrayB>)
.

Groups can contain subgroups (by using
each
andgroup
operations), and may be nested to any level. 
Multiple subgroupings or outputs can be created under the same group level, using multiple parallel
each
orall
clauses, and each one may be labelled using theas(mylabel)
construct. 
Each level of grouping specifies a set of aggregates to collect for all documents that belong to that
group (using the
output
operation): The documents in a group, retrieved using a specified summary class.
 The count of documents in a group.
 The sum, average, min, max, xor or standard deviation of an expression.

Each level of grouping may specify how to order its groups (using the
order
operation): Ordering can be done using any of the available aggregates.
 Multilevel grouping allows strict ordering where primary aggregates may be equal.
 Ordering is either ascending or descending, specified per level of ordering.

You may limit the number of groups returned for each level (using the
max
operation), returning only first n groups as specified by theorder
operation. 
You may count the number of unique groups for a level using the
count
aggregator. Note thatcount
operates independently of themax
clause.  You may paginate through group and hitlists using the "continuations" query parameter.
 You may group on multivalued attributes. Most grouping functions will just handle the elements of multivalued attributes separately, as if they were all individual values in separate documents.

The
interpolatedlookup
function will count elements in a sorted array that are less than an expression, with linear interpolation if the expression is between element values.
Select parameter language grammar
request ::= group [ "where" "(" ( "true"  "$query" ) ")" ] group ::= ( "all"  "each") "(" operations ")" [ "as" "(" identifier ")" ] operations ::= [ "group" "(" expression ")" ] ( ( "alias" "(" identifier "," expression ")" )  ( "max" "(" number ")" )  ( "order" "(" expList  aggrList ")" )  ( "output" "(" aggrList ")" )  ( "precision" "(" number ")" ) )* group* aggrList ::= aggr ( "," aggr )* aggr ::= ( ( "count" "(" ")" )  ( "sum" "(" exp ")" )  ( "avg" "(" exp ")" )  ( "max" "(" exp ")" )  ( "min" "(" exp ")" )  ( "xor" "(" exp ")" )  ( "stddev" "(" exp ")" )  ( "summary" "(" [ identifier ] ")" ) ) [ "as" "(" identifier ")" ] expList ::= exp ( "," exp )* exp ::= ( "+"  "") ( "$" identifier [ "=" math ] )  ( math )  ( aggr ) math ::= value [ ( "+"  ""  "*"  "/"  "%" ) value ] value ::= ( "(" exp ")" )  ( "add" "(" expList ")" )  ( "and" "(" expList ")" )  ( "cat" "(" expList ")" )  ( "div" "(" expList ")" )  ( "docidnsspecific" "(" ")" )  ( "fixedwidth" "(" exp "," number ")" )  ( "interpolatedlookup" "(" attributeName "," exp ")")  ( "math" "." ( ( "exp"  "log"  "log1p"  "log10"  "sqrt"  "cbrt"  "sin"  "cos"  "tan"  "asin"  "acos"  "atan"  "sinh"  "cosh"  "tanh"  "asinh"  "acosh"  "atanh" ) "(" exp ")"  ( "pow"  "hypot" ) "(" exp "," exp ")" ))  ( "max" "(" expList ")" )  ( "md5" "(" exp "," number "," number ")" )  ( "min" "(" expList ")" )  ( "mod" "(" expList ")" )  ( "mul" "(" expList ")" )  ( "or" "(" expList ")" )  ( "predefined" "(" exp "," "(" bucket ( "," bucket )* ")" ")" )  ( "reverse" "(" exp ")" )  ( "relevance" "(" ")" )  ( "sort" "(" exp ")" )  ( "strcat" "(" expList ")" )  ( "strlen" "(" exp ")" )  ( "size" "(" exp")" )  ( "sub" "(" expList ")" )  ( "time" "." ( "year"  "monthofyear"  "dayofmonth"  "dayofyear"  "dayofweek"  "hourofday"  "minuteofhour"  "secondofminute" ) "(" exp ")" )  ( "todouble" "(" exp ")" )  ( "tolong" "(" exp ")" )  ( "tostring" "(" exp ")" )  ( "toraw" "(" exp ")" )  ( "uca" "(" exp "," string [ "," string ] ")" )  ( "xor" "(" expList ")" )  ( "xorbit" "(" exp "," number ")" )  ( "ymum" "(" ")" )  ( "zcurve" "." ( "x"  "y" ) "(" exp ")" )  ( attributeName "." "at" "(" number ")")  ( attributeName ) bucket ::= "bucket" ( "("  "["  "<" ) ( "inf"  rawvalue  number  string ) [ "," ( "inf"  rawvalue  number  string ) ] ( ")"  "]"  ">" ) rawvalue ::= "{" ( ( string  number ) "," )* "}"
Output format
When grouping results, groups that contain outputs, group lists, and hit lists are generated. Group lists contain subgroups, and hit lists contain hits that are part of the owning group.
The identity of a group is held by its id. Scalar identities such as long, double and string, are directly available from the id, whereas range identities used for bucket aggregation are separated into the subnodes from and to. Refer to the result format reference.
Continue parameter
Pagination of grouping results are managed by "continuations". These are opaque objects that can be combined and resubmitted using the "continuations" annotation on the grouping step of the query to move to the previous or next page in a result list.
All root groups contain a single "this" continuation. That continuation represents the current view, and if submitted as the sole continuation it will reproduce the exact same result as the one that contained it. Other named continuations are available in the result, and these can be appended to the "this" continuation to perform the corresponding pagination operation. E.g. the "next" continuation of a group list can be used to move to the next page of groups in that list.
Any number of continuations can be combined in a query, but the first must always be the "this" continuation. E.g. you may simultaneously move both to the next page of one list, and the previous page of another.
If more than one continuation object are provided for the same group or hitlist, the one given last is the one that takes effect. This is because continuations are processed in the order given, and they replace whatever continuations they collide with.
If working programmatically with grouping, you will find the
Continuation
objects within
RootGroup
,
GroupList
and
HitList
result objects. These can then be added back into the continuation list of the
GroupingRequest
to paginate.
Here is an example of a query that provides a continuation to the grouping statement:
/search/?yql=select (…)  [{ 'continuations':['BGAAABEBCA'] }]all(…);
Labels
Lists created using theeach
keyword can be assigned a label using the construct each(...) as(mylabel)
.
The outputs created by that each clause will be identified by this label.
Aggregators
Group list aggregators  
Name  Description  Arguments  Result 

count  Counts the number of unique groups (As produced by the group clause).  None  Long 
Group aggregators  
Name  Description  Arguments  Result 
count  Increments a long counter everytime it is invoked.  None  Long 
sum  Sums the argument over all selected documents.  Numeric  Numeric 
avg  Computes the average over all selected documents.  Numeric  Numeric 
min  Keeps the minimum value of selected documents.  Numeric  Numeric 
max  Keeps the maximum value of selected documents.  Numeric  Numeric 
xor  XOR the values (their least significant 64 bits) of all selected documents.  Any  Long 
stddev  Computes the population standard deviation over all selected documents.  Numeric  Double 
Hit aggregators  
Name  Description  Arguments  Result 
summary  Produces a summary of the requested summary class.  Name of summary class  Summary 
When all arguments are numeric, the result type is resolved by looking at the argument types. If all arguments are longs, the result is an long, if at least one argument is a double, the result is a double.
When using order(), aggregators can also be used in expressions, in order to get increased control over group sorting. This does not work with expressions that takes attributes as an argument, unless the expression is enclosed within an aggregator.
Expressions
Arithmetic expressions  
Name  Description  Arguments  Result 

add  Add the arguments together.  Numeric+  Numeric 
+  Add left and right argument.  Numeric, Numeric  Numeric 
mul  Multiply the arguments together.  Numeric+  Numeric 
*  Multiply left and right argument.  Numeric, Numeric  Numeric 
sub  Subtract second argument from first, third from result, etc.  Numeric+  Numeric 
  Subtract right argument from left.  Numeric, Numeric  Numeric 
div  Divide first argument by second, result by third, etc.  Numeric+  Numeric 
/  Divide left argument by right.  Numeric, Numeric  Numeric 
mod  Modulo first argument by second, result by third, etc.  Numeric+  Numeric 
%  Modulo left argument by right.  Numeric, Numeric  Numeric 
neg  Negate argument.  Numeric  Numeric 
  Negate right argument.  Numeric  Numeric 
Bitwise expressions  
Name  Description  Arguments  Result 
and  AND the arguments in order.  Long+  Long 
or  OR the arguments in order.  Long+  Long 
xor  XOR the arguments in order.  Long+  Long 
String expressions  
Name  Description  Arguments  Result 
strlen  Count the number of bytes in argument.  String  Long 
strcat  Concatenate arguments in order.  String+  String 
Type conversion expressions  
Name  Description  Arguments  Result 
todouble  Convert argument to double.  Any  Double 
tolong  Convert argument to long.  Any  Long 
tostring  Convert argument to string.  Any  String 
toraw  Convert argument to raw.  Any  Raw 
Raw data expressions  
Name  Description  Arguments  Result 
cat  Cat the binary representation of the arguments together.  Any+  Raw 
md5  Does an md5 over the binary representation of the argument, and keeps the lowest 'width' bits.  Any, Numeric(width)  Raw 
xorbit  Does an xor of 'width' bits over the binary representation of the argument. Width is rounded up to a multiple of 8.  Any, Numeric(width)  Raw 
Accessor expressions  
Name  Description  Arguments  Result 
relevance  Return the computed rank of a document.  None  Double 
docidnsspecific  Return the docid without namespace.  None  String 
Applies only to streaming mode.  
ymum  Return the ymum part of docid.  None  Long 
Applies only to streaming search.  
<attributename>  Return the value of the named attribute.  None  Any 
Bucket expressions  
Name  Description  Arguments  Result 
fixedwidth  Maps the value of the first argument into consecutive buckets whose width equals the second argument.  Any, Numeric  NumericBucketList 
predefined  Maps the value of the first argument into the given buckets.  Any, Bucket+  BucketList 
Time expressionsUse the query parameter "timezone" to set the timezone to use when running these expressions. E.g.&timezone=GMT1 . See Sun's documentation
on TimeZone for format
reference.
 
Name  Description  Arguments  Result 
time.dayofmonth  Returns the day of month (131) for the given timestamp.  Long  Long 
time.dayofweek  Returns the day of week (06) for the given timestamp, Monday being 0.  Long  Long 
time.dayofyear  Returns the day of year (0365) for the given timestamp.  Long  Long 
time.hourofday  Returns the hour of day (023) for the given timestamp.  Long  Long 
time.minuteofhour  Returns the minute of hour (059) for the given timestamp.  Long  Long 
time.monthofyear  Returns the month of year (112) for the given timestamp.  Long  Long 
time.secondofminute  Returns the second of minute (059) for the given timestamp.  Long  Long 
time.year  Returns the full year (e.g. 2009) of the given timestamp.  Long  Long 
List expressions  
Name  Description  Arguments  Result 
size  Return the number of elements in the argument if it is a list. If not return 1.  Any  Long 
sort  Sort the elements in argument in ascending order if argument is a list If not it is a NOP.  Any  Any 
reverse  Reverse the elements in the argument if argument is a list If not it is a NOP.  Any  Any 
Other expressions  
Name  Description  Arguments  Result 
zcurve.x 
Returns the X component of the given zcurve encoded 2d point.
All fields of type "position" have an accompanying "<fieldName>_zcurve" attribute that can be decoded using this expression, e.g. zcurve.x(foo_zcurve) .
 Long  Long 
zcurve.y  Returns the Y component of the given zcurve encoded 2d point.  Long  Long 
uca  Converts the attribute string using unicode collation algorithm, useful for sorting.  Any, Locale(String), Strength(String)  Raw 
Single argument standard mathematical expressionsThese are the standard mathematical functions as found in the Java Math class.  
Name  Description  Arguments  Result 
math.exp  Double  Double  
math.log  Double  Double  
math.log1p  Double  Double  
math.log10  Double  Double  
math.sqrt  Double  Double  
math.cbrt  Double  Double  
math.sin  Double  Double  
math.cos  Double  Double  
math.tan  Double  Double  
math.asin  Double  Double  
math.acos  Double  Double  
math.atan  Double  Double  
math.sinh  Double  Double  
math.cosh  Double  Double  
math.tanh  Double  Double  
math.asinh  Double  Double  
math.acosh  Double  Double  
math.atanh  Double  Double  
Dual argument standard mathematical expressionsWe also implement a few other convenient expressions. One very nice for geometrical distance calculations.  
Name  Description  Arguments  Result 
math.pow  Return X^Y.  Double, Double  Double 
math.hypot  Return length of hypotenuse given X and Y sqrt(X^2 + Y^2).  Double, Double  Double 
Examples
TopN / Full corpus
Simple grouping where you count the number of documents in each group:
/search/?yql=select (…)  all(group(a) each(output(count())));
Two parallel groupings:
/search/?yql=select (…)  all(all(group(a) each(output(count()))) all(group(b) each(output(count()))));
Only the 1000 best hits will be grouped at each backend node. Lower accuracy, but higher speed:
/search/?yql=select (…)  all(max(1000) all(group(a) each(output(count()))));
In streaming search you may also group all searched documents by adding a where(true)
clause:
/search/?yql=select (…)  all(group(a) each(output(count()))) where(true);
Selecting groups
Perform a modulo 5 operation before selecting the group you want:
/search/?yql=select (…)  all(group(a % 5) each(output(count())));
Perform a + b * c
before selecting the group you want:
/search/?yql=select (…)  all(group(a + b * c) each(output(count())));
Grouping on maps
For streaming search, the field path syntax may also be used when searching, which enables structs and maps to be searched. The following syntax can be used when grouping maps, and will create a group for values whose keys match "foo":
/search/?yql=select (…)  all(group(mymap{"foo"}) each(output(count())));
Locale aware sorting
Groups are sorted using locale aware sorting, with the default and primary strength values, respectively:
/search/?yql=select (…)  all(group(s) order(max(uca(s, "sv"))) each(output(count())));
/search/?yql=select (…)  all(group(s) order(max(uca(s, "sv", "PRIMARY"))) each(output(count())));
Ordering groups
Perform a modulo 5 operation before selecting the group you want. The groups are then ordered by their aggregated sum of attribute "b":
/search/?yql=select (…)  all(group(a % 5) order(sum(b)) each(output(count())));
Perform a + b * c
before selecting the group you want. Ordering is given by the
maximum value of attribute "d" in each group:
/search/?yql=select (…)  all(group(a + b * c) order(max(d)) each(output(count())));
Take the average relevance of the groups and multiply it with the number of groups to get a cumulative count:
/search/?yql=select (…)  all(group(a) order(avg(relevance()) * count()) each(output(count())));
You can not, however, directly reference an attribute in your order clause, as this:
/search/?yql=select (…)  all(group(a) order(attr * count()) each(output(count())));
But, you can do this:
/search/?yql=select (…)  all(group(a) order(max(attr) * count()) each(output(count())));
Collecting aggregates
Simple grouping where you count number of documents in each group and return the best hit in each group:
/search/?yql=select (…)  all(group(a) each(max(1) each(output(summary()))));
Also return the sum of attribute "b":
/search/?yql=select (…)  all(group(a) each(max(1) output(count(), sum(b)) each(output(summary()))));
Also return an xor of the 64 most significant bits of an md5 over the concatenation of attributes "a", "b" and "c":
/search/?yql=select (…)  all(group(a) each(max(1) output(count(), sum(b), xor(md5(cat(a, b, c), 64))) each(output(summary()))));
Predefined buckets
Group on predefined buckets for raw attribute and use infinity to make sure the buckets cover the whole possible range:
/search/?yql=select (…)  all(group(predefined(r, bucket(inf, {0, 'a', 3}), bucket({1, 'u', 4}, inf))) each(output(count())));
Standard mathematical start and end specifiers may be used to define the width of a bucket. The "(" and ")" evaluates to "[" and ">" by default. Here, make a bucket that can only with one exact group, and use different width specifiers:
/search/?yql=select (…)  all(group(predefined(r, bucket[inf, "bar">, bucket["bar"], bucket<"bar", inf])) each(output(count())));
Grouping
Single level grouping on "a" attribute, returning at most 5 groups with full hit count as well as the 69 best hits.
/search/?yql=select (…)  all(group(a) max(5) each(max(69) output(count()) each(output(summary()))));
Two level grouping on "a" and "b" attribute:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(group(b) max(5) each(max(69) output(count()) each(output(summary()))))));
Three level grouping on "a", "b" and "c" attribute:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(group(b) max(5) each(output(count()) all(group(c) max(5) each(max(69) output(count()) each(output(summary()))))));
As above example, but also collect best hit in level 2:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(group(b) max(5) each(output(count()) all(max(1) each(output(summary()))) all(group(c) max(5) each(max(69) output(count()) each(output(summary()))))));
As above example, but also collect best hit in level 1:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(max(1) each(output(summary()))) all(group(b) max(5) each(output(count()) all(max(1) each(output(summary()))) all(group(c) max(5) each(max(69) output(count()) each(output(summary()))))));
As above example, but using different document summaries on each level:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(max(1) each(output(summary(complexsummary)))) all(group(b) max(5) each(output(count()) all(max(1) each(output(summary(simplesummary)))) all(group(c) max(5) each(max(69) output(count()) each(output(summary(fastsummary)))))));
Group on fixed width buckets for numeric attribute, then on "a" attribute, count hits in leaf nodes:
/search/?yql=select (…)  all(group(fixedwidth(n, 3)) each(group(a) max(2) each(output(count()))));
As above example, but limiting groups in level 1, and returning hits from level 2:
/search/?yql=select (…)  all(group(fixedwidth(n, 3)) max(5) each(group(a) max(2) each(output(count()) each(output(summary())))));
Deep grouping with counting and hit collection on all levels:
/search/?yql=select (…)  all(group(a) max(5) each(output(count()) all(max(1) each(output(summary()))) all(group(b) each(output(count()) all(max(1) each(output(summary()))) all(group(c) each(output(count()) all(max(1) each(output(summary())))))))));
Time aware grouping
Group by year:
/search/?yql=select (…)  all(group(time.year(a)) each(output(count())));
Group by year, then by month:
/search/?yql=select (…)  all(group(time.year(a)) each(output(count()) all(group(time.month(a)) each(output(count())))));
Group by year, then by month, then day, then by hour:
/search/?yql=select (…)  all(group(time.year(a)) each(output(count()) all(group(time.monthofyear(a)) each(output(count()) all(group(time.dayofmonth(a)) each(output(count()) all(group(time.hourofday(a)) each(output(count())))))))));
Groups today, yesterday, lastweek, and lastmonth
using predefined
aggregator, and groups each day within each of these separately:
/search/?yql=select (…)  all(group(predefined((now()  a) / (60 * 60 * 24), bucket(0,1), bucket(1,2), bucket(3,7), bucket(8,31))) each(output(count()) all(max(2) each(output(summary()))) all(group((now()  a) / (60 * 60 * 24)) each(output(count()) all(max(2) each(output(summary())))))));
Counting unique groups
The count
aggregator can be applied on list of groups to determine the number of
unique groups without having to explicitly retrieve all groups. Another use case for this aggregator is
counting the number of unique instances matching a given expression.
The following query outputs the number of groups, which is equivalent to the number of unique values for attribute "a".
/search/?yql=select (…)  all(group(a) output(count()))
The following query outputs the number of unique string lengths for the attribute "name".
/search/?yql=select (…)  all(group(strlen(name)) output(count()))
The following query outputs the sum of the "b" attribute for each group in addition to the overall group count.
/search/?yql=select (…)  all(group(a) output(count()) each(output(sum(b))))
The max
clause is used to restrict the number of groups returned.
The query outputs the sum for the 3 best groups. The count
clause
outputs the actual number of groups (potentially >3).
/search/?yql=select (…)  all(group(a) max(3) output(count()) each(output(sum(b))))
The following query outputs the number of top level groups, and for the 10 best groups, outputs the number of unique values for attribute "b".
/search/?yql=select (…)  all(group(a) max(10) output(count()) each(group(b) output(count())))
Using the grouping session cache
When having multilevel grouping expressions, the search query is normally rerun for each level. The drawback of this is that if you have an expensive ranking function, the query will take more time than strictly necessary.
To avoid this, you can set the groupingSessionCache
query flag. This causes the query and grouping expression to be performed
only once.
However, the flag is only useful if the grouping expression does
not have a order()
clause.
The drawback of using this flag is that when max()
is
specified in the grouping expression, it might cause inaccuracies in
aggregated values such as count()
. We therefore recommend that
you test whether or not this is an issue for your queries, and (if it is an
issue) adjust the precision
parameter to still get correct
counts.
Grouping of multivalue attributes
Some grouping operators may be used with multivalue attributes. Note that using a multivalued attribute (such as an array of doubles) in a grouping expression is likely to have a large, adverse impact on performance, particularly if the set of hits to be processed is large, since it means a large amount of data is streamed through the CPU. Such operations is therefore likely to hit a bottleneck on memory bandwidth.
Caveats
For streaming search, multivalue fields such as maps, arrays etc. can be used for grouping. However, using aggregation functions such as sum() on such fields can give misleading results. Assume a map from strings to integers, where the strings are some sort of key you wish to use for grouping. The following expression will provide the sum of the values for all keys:
/search/?yql=select (…)  all(group(mymap.key) each(output(sum(mymap.value))));
and not the sum of the values within each key, as one would expect. It is still, however, possible to run the following expression to get the sum of values within a specific key:
/search/?yql=select (…)  all(group(mymap{"foo"}) each(output(sum(mymap.value))));
This syntax is mapspecific, it does NOT apply to weighted sets.
Using sum, max, etc on a multivalued attribute
Doing an operation such as output(sum(myarray))
will
run the sum over each element value in each document. The result
is the sum of sums of values. Similarly max(myarray)
will yield the maximal element over all elements in all documents,
and so on.
Array at: element access
The expression array.at(myarray, idx)
will yield one
value per document by evaluating the idx
expression
and using it as an index into the given array. The expression will
be capped to the range [0, size(myarray)1]
.
If it's larger than the array size you always get
the last element, while if it's smaller than zero you always get
the first element. This expression can then be used to build
bigger expressions such as output(sum(array.at(myarray, 0)))
which will sum the first element in the array of each document.
Interpolated lookup (BETA)
The operation interpolatedlookup(myarray, expr)
is
intended for generic graph/function lookup. The data
in myarray
should be numerical values sorted in
ascending order. The operation will then scan from the start
of the array to find the position where the element values
become equal to (or greater than) the value of
the expr
lookup argument, and return the index
of that position.
When the lookup argument's value is between two consecutive array
element values, the returned position will be a linear
interpolation between their respective indexes. The return
value is always in the range [0, size(myarray)1]
of the legal index values for an array.
Given an example where myarray
is a sorted array of
type array<double>
in each document.
The expression interpolatedlookup(myarray, 4.2)
is now a perdocument expression that first evaluates the lookup
argument, here a constant expression 4.2, and then looks at
the contents of myarray
in the document.
The scan starts at the first element and proceeds until it hits
an element value greater than 4.2 in the array. This means that:
 If the first element in the array is greater than 4.2, the expression returns 0.
 If the first element in the array is exactly 4.2, the expression still returns 0.
 If the first element in the array is 1.7 while the second element value is exactly 4.2, the expression return 1.0 – the index of the second element.

If all the elements in the array are less than 4.2,
the last valid array index
size(myarray)1
is returned.  If the 5 first elements in the array have values smaller than the lookup argument, and the lookup argument is halfway between the fifth and sixth element, a value of 4.5 is returned – halfway between the array indexes of the fifth and sixth elements.

Similarly, if the elements in the array are
{0, 1, 2, 4, 8}
then passing a lookup argument of "5" would return 3.25 (linear interpolation betweenindexOf(4)==3
andindexOf(8)==4
).
Use case: Impression counting
If you have the impression logs for a specific user, you can make a function that maps from rankscore to the number of impressions an advertisement would get. So you would have a table like this:
Score Integer (# impressions for this user) 0.200 0 0.210 1 0.220 2 0.240 3 0.320 4 0.420 5 0.560 6 0.700 7 0.800 8 0.880 9 0.920 10 0.940 11 0.950 12Storing just the first column (the rank scores, including a rank score for 0 impressions) in an array attribute named "impressions", we could then use the grouping operation
interpolatedlookup(impressions, relevance())
to figure out how many times a given advertisement would have
been shown to this particular user.
So if the rankscore is 0.420 for a specific user/ad/bid
combination, then interpolatedlookup(impressions,relevance())
would return 5.0. If the the bid is
increased so the rankscore gets to 0.490 it would get 5.5 as the
return value instead.
In this context a count of 5.5 isn't meaningful for the past of
a single user, but it gives more information that may be used as
a forecast. Summing this across many different users may then
be used to forecast the total of future impressions for the
advertisement.