A query profile is a named set of query parameters, defined in the application package.
When a query request names a profile, the parameters in that profile are applied to the request.
This has two main benefits:
Clients send only the profile name,
instead of having to manage and send every parameter a use case needs.
The parameters for a use case can be changed by redeploying the application,
without changing any clients.
Query profiles also make it easy to treat different groups of queries differently.
For example, use them to run bucket tests,
where a part of the traffic gets experimental settings,
or to vary behavior by customer, user type, region, or frontend.
This guide explains how to create and use query profiles.
For the full syntax, see the query profile reference.
Using a Query Profile
A query profile is an XML file that lists parameter names and their values:
You can add any number of query profile files to this directory.
If a query profile contains errors, such as invalid syntax or infinite reference loops, deployment fails.
To use a query profile in a query request, pass its name in the queryProfile parameter:
queryProfile=MyProfile
If the request does not specify a query profile,
the profile named default is used.
If there is no default profile, no profile is used.
If queryProfile is set but does not match an existing profile,
an error is returned.
For example, this sets a timeout of 200 ms for all queries that don't specify a query profile:
Parameter values, whether they come from a query profile or from the request,
are available as query properties.
To look up a value in a Searcher component, use:
query.properties().get("myVariable")
Property names are case-sensitive.
Example
This query profile defines a YQL query that filters on city
using the IN operator,
with the list of cities inserted by substitution
of the cities parameter:
<query-profileid="city-filter"><fieldname="yql">select * from restaurant where userQuery() and city in (%{cities})</field><fieldname="cities">""</field></query-profile>
The IN operator requires the field to use match: word:
field city typestring{indexing:summary|indexmatch: word}
A query that passes the cities to substitute into the YQL string:
$ vespa query \
queryProfile=city-filter \
cities='"berlin","paris"' \
query='what the user typed'
The application can then use the city-filter profile when the user has selected cities,
and a no-filter profile otherwise:
<query-profileid="no-filter"><fieldname="yql">select * from restaurant where userQuery()</field></query-profile>
$ vespa query \
queryProfile=no-filter \
query='what the user typed'
Overrides
The values in a query profile are used as if they were set directly in the request.
If a parameter is set both in the request and in the profile,
the request value takes precedence by default.
To make a profile value take precedence instead, set
the overridable attribute
of the field to false:
To give structure to the parameters, a query profile value can be
a reference to another query profile instead of a string.
The referenced profile then acts as a map
(or a struct, if types are used) within the referencing profile.
The parameter names in the nested profile are prefixed by the name of the
referencing field and a dot. For example:
References can be nested to any depth, producing parameter names with multiple dots.
Like any other parameter, a dotted parameter can be overridden in the request
by using its full dotted name.
The request can also set which profile a reference points to.
This lets the request choose not only the top-level profile,
but also any of the nested profiles.
For example, this request replaces the user reference in the example above
with another profile:
The ref: prefix is required.
It tells Vespa to set user to the query profile with the given id,
rather than to the string MyOtherUserProfile.
Inheritance
A query profile can inherit one or more other query profiles.
This is useful when several use cases share a common set of parameters,
and only a smaller set varies between them.
To inherit another query profile, reference it in the
inherits attribute:
When this profile is used, the parameters of MyBaseProfile are included
exactly as if they were written in this profile.
To inherit multiple profiles, list their ids separated by spaces.
The order matters: if a parameter is set in more than one inherited profile,
the first value found in a depth-first, left-to-right search is used.
A parameter set in the inheriting profile always overrides the same parameter in an inherited one.
Value Substitution
Query profile values can contain substitution strings of the form
%{property-name}. For example:
A substitution string is replaced by the value
of query.properties().get("property-name")at the time of the lookup.
This means the substituted value can come from a variant,
an inherited profile, a value set at run time,
or a referenced query profile. Details:
No substitution is performed in values set at run time.
If the referenced value is null, it is replaced by the empty string.
Unclosed substitutions cause an error at deploy time, but unknown properties do not,
since they may be set at run time. If they are not, they are replaced by the empty string.
Recursive substitution works as expected, but there is no loop detection.
Local substitution
To substitute a value from the same query profile (or variant),
prefix the property name with a dot:
Local substitutions are verified at deploy time,
and deployment fails if the referenced property is not found.
Query Profile Variants
Sometimes the values in a query profile should depend on
the values of some parameters in the request.
For example, the values may depend on the region
the request comes from (region), the kind of device (model),
and the bucket
the request belongs to (bucket).
All of this can be expressed in a single query profile,
by defining nested variants of the profile for the relevant combinations of request values.
The dimensions element
names the request parameters to vary over,
and the for attribute
of each nested profile gives the values it applies to.
A complete example:
<query-profileid="multiprofile1"><!-- A regular profile may define "virtual" children within itself --><!-- Names of the request parameters defining the variant profiles of this. Order matters as described below.
Each individual value looked up in this profile is resolved from the most specific matching virtual
variant profile --><dimensions>region,model,bucket</dimensions><!-- Values may be set in the profile itself as usual, this becomes the default values given no matching
virtual variant provides a value for the property --><fieldname="a">My general a value</field><!-- The "for" attribute in a child profile supplies values in order for each of the dimensions --><query-profilefor="us,nokia,test1"><fieldname="a">My value of the combination us-nokia-test1-a</field></query-profile><!-- Same as [us,*,*] - trailing "*"'s may be omitted --><query-profilefor="us"><fieldname="a">My value of the combination us-a</field><fieldname="b">My value of the combination us-b</field></query-profile><!-- Given a request which matches both the below, the one which specifies concrete values to the left
gets precedence over those specifying concrete values to the right
(i.e the first one gets precedence here) --><query-profilefor="us,nokia,*"><fieldname="a">My value of the combination us-nokia-a</field><fieldname="b">My value of the combination us-nokia-b</field></query-profile><query-profilefor="us,*,test1"><fieldname="a">My value of the combination us-test1-a</field><fieldname="b">My value of the combination us-test1-b</field></query-profile></query-profile>
Variants and Inheritance
Variants can be defined at several levels in an inheritance hierarchy.
The variant dimensions are inherited from parent to child
with the usual precedence rules (depth-first, left-to-right),
so a parent profile can define the dimensions, and a child the values that vary over them.
Variant resolution within a profile takes precedence over resolution in its parents.
For example, a default value for a property in a child profile is chosen
over a perfect variant match in an inherited profile.
Variants can specify their own inherited profiles:
Values are then resolved from this profile and its inherited profiles, interleaved
in the variant resolution order (by default, most specific first).
In decreasing priority:
1. Value in the highest-priority variant
2. Value inherited by the highest-priority variant
3. Value in the next highest-priority variant
4. Value inherited by the next highest-priority variant
…
n. Value defined at the top level of the profile
n+1. Value inherited by the profile
Query Profile Types
Query profiles can optionally be type checked.
To turn on type checking, reference a query profile type from the query profile.
The type lists which parameters the profile can contain,
whether other parameters are allowed, and so on.
Reference a query profile type with the
type attribute:
This type allows profiles to contain these three parameters,
and specifies that user must reference a query profile of type MyUserProfileType.
A type can also make parameters mandatory,
disallow parameters that are not listed (strict),
inherit other types, and so on.
See the query profile reference
for the full syntax.
If the base profile type is strict, it must inherit a built-in query profile type,
see the strict reference documentation.
To deploy a query profile type, add a file named [query-profile-type-name].xml
to the search/query-profiles/types directory in the application package.
Query profile types are useful even if query profiles are not used to set any values.
Since a type defines the names, types, and structure of the parameters a request can contain,
it can be used to define, restrict, and validate query requests.
When a typed query profile is used, the built-in Query API parameters are also type checked,
so types can restrict which parameters a request can set, or require that some are always set.
The built-in parameters are defined in a set of query profile types that are always present,
and that application-defined types can inherit and reference.
These built-in types are described in the Query API reference.
Path Matching
By adding <match path="true"> to a profile type,
profiles of that type are looked up by path matching instead of the default exact name matching.
Path matching treats a profile name as a slash-separated path,
so a reference to a more specific path matches a profile with a less specific path.
The most specific match is used. For example:
Given the query profile names:
a1
a1/b1
Then:
a1/b1/c1/d1 resolves to a1/b1
a1/b resolves to a1
a does not resolve
This lets you give every client or bucket its own query profile id
without creating a separate profile for each one.
If a client or bucket later needs its own configuration,
you can add a profile for it without changing the client, since it already sends a specific id.
Versioning
Query profiles (and types) can exist in multiple versions at the same time.
Wherever a query profile (or type) is referenced by name,
a version can be appended after a colon, e.g. MyProfile:1.2.3.
The version is resolved: if no version is given, the highest known version is used.
If the version is only partially specified, as in MyProfile:1,
the highest version starting with 1 is used.
Where a query profile (or type) is defined, the id can include a version after a colon:
In a definition, omitted parts of the version are taken to be 0,
so id="MyProfile:1" is the same as id="MyProfile:1.0.0".
A query profile (or type) that specifies a version in its id
must have a file name that includes the same version after the name,
separated by a dash, e.g. MyProfile-1.2.3.xml.