Keywords
The syntax descriptions on this page use angle brackets (< >
) to call out various entities in the syntax, which will be defined after the example unless it is obvious what they mean.
Ellipses (...
) mean that particular pattern can be repeated several times.
Brackets ([ ]
) denote optional sections.
@ Directives
Directives are annotations on an entity in FDL that modifies it's behavior in some way. They are similar to GraphQL directives. Depending on the directive, it can be placed after the name of a new feature or event that you are writing, or after a field definition. For example:
feature example
@no_gate ## don't allow feature gating on this feature
{
obsolete: Int! @deprecated( reason: "This is old, you can remove it from the code")
}
@deprecated
@deprecated[ (reason: <reason> ) ]
@elapsed
@elapsed(kind: "session_end")
@elapsed(kind: "until", path: ["FeatureName","FeatureName.EventName","AbstractEvent"])
@external
See External Outputs
@external( values: ["popularity", "distance"] )
@hint
The @hint
directive adds a type hint to some part of the FDL schema definition. Type hints are used to augment downstream type information for FDL in certain target systems.
FDL's string type is an arbitrary length string. Some downstream systems (most notably redshift) do not have downstream arbitrary length strings. You can use the length type hint on a string to change the default string length for these downstream systems:
aStringField : String! @hint(length: 500) ## This string will appear as varchar(500) in redshift
@is_default( out: output name
)
Default values represent the current state of your application. The are changed by running experiments to test out new configurations, and by rolling out changes to subsets of your traffic. This directive will set the target to true
if the given output is the current default, false
if set by a running experiment or a partial rollout. The target of this directive must be a nullable boolean. See also @variant_id and @variant_name.
feature
{
output {
aString : String!
aString_default: Boolean @is_default(out: "aString")
}
}
@mutable
see Mutable Data
@no_gate
Remove the feature gate from the given feature.
@no_log
Do not write this field to the data warehouse. This is useful for PII data that you do not want to store, but needs to be available on the front ends. The field will appear as usual in the front end APIs, but will never be written to persistent storage.
@off_by_default
When added to a feature definition, causes the feature to be inactive unless someone explicitly activates it on the feature's web page.
Normally, features are immediately available once the code for the feature is deployed into a development environment. The default values for the feature's output are all accessible through the client APIs.
However, when @off_by_default
is specified, the feature will instead be marked inactive and no values will be available.
@per
see Per Metrics
@persistent_key
see Persistent Keys
@redis
The @redis
directive allows to read and write data to a redis cluster. Please reach out to Causal support if you like to enable this feature.
The @redis
directive requires the op
attribute. This is the templated redis command which will be executed when the fdl field is updated or initialized. The template uses FDL field names surrounded by curly braces to denote a value that will be templated at runtime.
In this example, Feature.ClickEvent has the redis directive.
session
{
args
{
deviceId : String! @persistent_key nullableArg : String
}
}
feature Feature
{
args {}
event ClickEvent
{
value: String! @redis(op: "HMSET {deviceId} clickValue {value}")
}
}
HMSET
is the name of the redis operation.{deviceId}
is a field on the session.clickValue
is a string literal and will not be translated.{value}
in this example{value}
is a templated value on an event.
The redis template will search for fields on parent objects if the field is not found on the current object.
The redis directive can also read in redis values and set them on fdl fields if the field is inside a plugin block.
Finally, the @redis
directive can be placed on the session object to perform redis operations when a session is first created. This can be used to set the TTL on the redis object.
@sample
The @sample
directive allows you to possibly discard data when a session is finished. This directive can be placed on a feature itself or on a nullable field (argument and/or output) within a feature. Currently, the only supported sampling criteria is features that have events where=events
. If the user did not trigger an event on that feature then the fields with the sample directive will be assigned to null. When the same directive is placed on the feature itself, the whole impression is dropped.
In addition, a rate parameter can be added which will keep the data if the hash of the split key is above that value. The rate's value must be an integer between 0 and 100. The default value, if rate is not specified, is 100. With a rate below 100, If the user triggered events on the impression and the hash of the split key falls below that value then data will be dropped as described above.
On a field:
listOfStrings : [String!] @sample(where: events, rate:50)
On a feature:
feature MyFeature
@sample(where: "events", rate: "50%")
{
...
}
@session_key
see Session Keys
@split_key
@variant_id( out: output name
)
If the given output was set by an experiment, return that variant's id. Null if the given output is set to the default value. See also @is_default and @variant_name.
feature
{
output {
aString : String!
aString_variant_id: ID @variant_id(out: "aString")
}
}
@variant_name( out: output name
)
If the given output was set by an experiment, return that variant's name. Null if the given output is set to the default value. See also @is_default and @variant_id.
feature
{
output {
aString : String!
aString_variant_id: String @variant_name(out: "aString")
}
}
args
feature <feature name>
{
args {
[ "<description>" ]
<arg name> : <arg type> [ = <default value> ] ...
}
}
event
The event keyword declares an event that you'd like to record and save to your data warehouse. Causal allows you to construct experiment metrics and audiences with these events.
Feature Events
Declaring an event inside a feature will tie that event to that particular feature. Causal will automatically collect these events and put them on the feature impression's row. In addition, you'll be able to create per impression metrics using these events and their feature's impressions.
feature <feature name>
{
[ "<description>" ]
event
{
[ "<field description>" ]
<field name> : <field type> [ = <default value> ] ...
}
}
Session Events
Declaring an event at the session level will tie that event to the user session as opposed to and feature impression. Use this form to collect events that are not associated with a particular impression, but still are important for measuring success. Session events appear in the session table in your data warehouse.
session
{
[ "<description>" ]
event
{
[ "<field description>" ]
<field name> : <field type> [ = <default value> ] ...
}
}
Offline Events
Declaring an offline event will allow you to define metrics that occur off site. For example, your customers may convert at a brick and mortar location, or on a partner's website. An offline event will create a new table for that event, with one row per occurrence.
You may add the @per directive to one or more of the fields in your offline event definition. The fields marked as @per must match exactly one of the @per fields in your session definition (or the @persistent_key). This makes it possible to use these offline events for automatic metric calculation using the tools metrics builder. An offline metric will appear as on option in the metric builder when the associated @per field is selected as the grouping criteria.
[ "<description>" ]
offline event <event-name>
{
[ "<field description>" ]
<field name> : <field type> [ = <default value> ] ... [ @per ]
}
After you rerun the compiler on the updated FDL, you will see new static methods on the SessionRequest object to signal an offline event. Using Java as an example, they will be in the form SessionRequest.signal<event-name>(args...)
Abstract Events
Defining an abstract event at the top level will not actually allow you to signal the event. However, you may import it into a feature, session, or offline event.
[ "<description>" ]
event
{
[ "<field description>" ]
<field name> : <field type> [ = <default value> ] ...
}
namespace
namespace <dotted name>;
The namespace
keyword tells Causal what package or namespace to generate code
in for languages that support it (currently Java and Avro schemas). If you have
more that 1 Causal account in your organization, you can choose different
namespaces so your code doesn’t conflict.
If no namespace is specified in the file, the default is io.causallabs.generated
.
output
feature <feature name>
{
output {
[ "<description>" ]
<output name> : <output type> = <default value> ...
}
}
session
session {
## events can also be defined outside of features. A session event happens online
## while a user event can happen anywhere through a bulk upload mechanism
"The user opened an email that we sent them"
event open_email {
campaign_id: String!
}
"The user used a discount code we provided"
event used_discount_code {
discount_code: String!
}
}
Event may occur outside of features. These are defined at the session level, so are not tied to any feature impression. Instead they are just recorded on the user's session.
uaparser
session @uaparser {
...
}
The uaparser directive will use the useragent string to infer new columns in your session warehouse table. This directive works correct if the session was initiated by a browser using the typescript front end.
- ua_browser_family: The family of the browser.
- ua_browser_version: The version of the browser.
- ua_device_family: If the browser is a mobile device then the family name of the device.
- ua_os_family: The operating system family name.
- ua_os_version: The version # of the operating system.