2 Getting Started with AMDL Syntax
AMDL (ARIC Modelling Data Language) allows you to create a wide-variety of rules for the Fraud Transaction Monitoring System through the Fraud Transaction Monitoring Portal. Before you create rules using the rich AMDL expressions, you will need to understand the prerequisites and gain familiarity with a basic rule.
2.1 Prerequisites
Before using AMDL in the Fraud Transaction Monitoring System, you need to be set up with the user role of Risk Manager with the appropriate permissions. A Risk Manager can create and edit rules, as well as push rules to the Live environment.
You should also have some knowledge of declarative programming languages in order to understand how to build and manipulate rules using AMDL.
Before creating rules Fraud Transaction Monitoring System, you need to be set up with the user role of Risk Manager with the appropriate permissions. A Risk Manager can create and edit rules, as well as push rules to the Live environment.
Creating fraud rules requires you to use AMDL (ARIC Modelling Data Language). You should also have some knowledge of declarative programming languages in order to understand how to build and manipulate rules using AMDL. However, an indepth knowledge is not required.
2.2 Creating a Rule
A rule is the fundamental building block that contains AMDL expressions. Alerts and tags are the outputs that are triggered from a rule to inform of changes.
A basic rule consists of various components that is entered in the AMDL syntax. This includes:
-
Alerts and tags
-
Event type
-
Rulename
-
Events
-
State information (see Adding State Information to a Rule)
This example rule sends an alert when a card transaction above the figure of 10000 is authorised.
@alert
@eventType("cardRT")
@eventType("cardNRT")
rules.highValue:
(event.msgType.lowercase() == "authorisation" &&
event.msgStatus.lowercase() == "new") &&
event.baseValue > 10,000
Using the Rule Builder interface in the Fraud Transaction Monitoring Portal you can add AMDL expressions. The Fraud Transaction Monitoring Portal also includes a set of for rules, represented as folders. To help you save time in rule building, Fraud Transaction Monitoring Portal includes the accountEntityId and the cardEntityId folders that contain pre-configured rules.
More details on customising rules with AMDL are described in Customising Business Rules in AMDL
2.2.1 Creating a New Rule
You can create a new rule in an existing directory, or you can specify your own directory and its location.
- Click + Create definition. A window displays.
- Select a directory for the new rule.
- To choose a different location, click Create directory. Then select a location in Parent directory and type in a Directory name.
- Click Create. You can then enter your rule expression.
2.2.2 Selecting an Existing Rule
You can expand the folder items for selecting an existing rule to update.
2.3 Alerts and tags
Alerts and tag contain a specific syntax. An alert, represented as @alert
, flags an event in the Fraud Transaction Monitoring System. Flagging the alert provides a prompt so that a user can prioritise, investigate and review high-risk events.
Tags, represented as provide additional information to users on why an alert was raised. They can also trigger automated decisions such as a soft decline (request chip and pin entry at the terminal for card present transactions), a hard decline of a transaction and a block of a card. The tags appear in the Fraud Transaction Monitoring Portal associated with the event or alert they were added to. The tags also exist in the output the fraud system produces in response to a real-time event.
You can alter the above rule to include the following tags:
@alert
@tag("High value transaction or account transfer")
@tag(action="BLOCK")
@eventType("cardRT")
@eventType("cardNRT")
rules.highValue:
(event.msgType.lowercase() == "authorisation" &&
event.msgStatus.lowercase() == "new") &&
event.baseValue > 10,000
This rule produces a tag with the namespace of action and value "BLOCK", and another which displays as the text "High value transaction or account transfer" in the Fraud Transaction Monitoring Portal.
The general form of the @tag annotation is @tag (<namespace>="<value>","<namespace>="<value>")
You can add more than tag by adding the @tag annotation multiple times. Or, you can add multiple tags using the same annotation:
@tag (<namespace1>="<value1>", <namespace2>="<value2>"...)
To add multiple tags in the same namespace, use this syntax:
@tag (<namespace1>="<value1>", <namespace1>="<value2>"...)
If you do not provide a namespace, you can use a default namespace (_tag
). If the namespace is unimportant, you can write...
. The portal displays this tag without a namespace.
2.4 eventType
This is the type of transaction in the fraud rule. This example includes the eventType as real-time and non-real-time transactions, represented as @eventType("cardRT")
and @eventType("cardNRT")
. The eventType acts as an annotation where it limits the events that are acted upon in a rule. In this example, the rule does not act on events involving cash transactions. However, the rule acts on card events.
2.5 Rule name
This is the name of the rule used. In this example, the rule is called "highvalue", which has the syntax of rules.highvalue
:.
The general syntax of a rule is as follows:
rules.<rule name>:<Boolean expression>
A rule is an AMDL expression defined in the "rules" scope, and consists of a Boolean expression which is evaluated for each event that passes through the system. Each AMDL expression applies to one particular entity type, for example cards or merchants, and evaluates for each entity of that type in event. If the expression evaluates to true, the rule has 'triggers' on the event.
2.6 Events
An event represents a type of activity. The syntax of an event must match an event schema. Any AMDL expression can refer to data contained in the event payload, using the event.fieldName
syntax. In this example, this is the message type, and message status data and base value of the transaction. This is represented as event.msgType
, event.msgStatus
, event.basevalue
. There is also a condition associated with each event, where the message must appear in lower case, must be a new, and be an authorisation for amounts above 10,000. This is represented in the following syntax:
(event.msgType.lowercase() == "authorisation" &&
event.msgStatus.lowercase() == "new") &&
event.baseValue > 10,000
2.6.1 JSON Schema in Events
The Fraud Transaction Monitoring System system is event driven. The following shows an example event, illustrating the structure of the JSON data with the data that is stored in respective data types, for example, date and time in "expiry"
.
{
"eventId": "a78e098d0bc7",
"eventType": "transaction",
"eventTime": "2019-05-05T18:02:55Z",
"customerId": "3263827",
"merchantId": "THX1138",
"customerSegment": "B",
"merchantCategoryCode": "1234",
"amount": {
"value": 100,
"currency": "EUR",
"baseValue": 85.70,
"baseCurency": "GBP"
},
"deviceData": {
"deviceId": "a85531c1-02d8-44ed-964f-0706155209c7",
"deviceType": "Android",
"OSversion": "10.0.1",
"deviceManufacturer": "CunningBadger",
"deviceModel": "Slow 2.0"
},
"paymentMethod": {
"methodType": "card",
"methodId": "WEA798GHSET98ERGX",
"methodDetails": {
"issuer": "Imperial Bank of Wales",
"BIN": "123456",
"expiry": "2020-12-01"
}
}"
transactionType": "CP",
"accepted": true
}
If there are several nested levels of JSON objects within the event, they can be accessed in a similar way to JSON objects, using periods to denote level transitions. For example, to reference the issuer field in the example transaction event above:
event.paymentMethod.methodDetails.issuer
Alternatively, you can use the square-bracket map accessor syntax, for example, ["level2field"]["level3field"]
) to access one or more levels. You may need to do this if the event.topLevelField
property names are reserved for AMDL keywords such as "state" or "values", for example, or if the field names begin with numbers:
event.paymentMethod["methodDetails"]["issuer"]
Note that this syntax cannot be used for root-level fields within the event data, as the AMDL parser expects an event at the beginning of any reference to event data.
When you write a rule, you write it against a specific entity type. This is because the alert that is raised is against the entity of that type.
2.6.2 Entity Meta-Variables
Meta-variables are the state._type
and state._id
. These contain the entity type and entity ID values that can be accessed in AMDL expressions (in both cases represented as a string). These are particularly useful where there are two entities of a given type within a single event.
For example, if a payment event contains two customer entities, acting as the payer and the payee, it might be useful to write an expression that can distinguish whether the entity being evaluated is the payer or payee. If the event contains a payerId
and payeeId
field, you can distinguish between the payer and payee entity simply by testing whether the ID of the current entity matches the payer ID or the payee ID.
This rule, for example, only triggers an alert for the payer if they are on a payer watchlist, or for the payee if they are on a payee watchlist.
@alert@eventType("payment")
rules.payerOrpayeeOnWatchList:
( state._id == event.payerId && lists.payerWatchList ~# event.payerId )
||
( state._id == event.payeeId &&
lists.payeeWatchList ~# event.payeeId )
These meta-variables avoid an alert being generated for the payee entity when the payer is the one on the watchlist, and vice versa. Meta-variables are also useful in cross-entity state references in Business Rules (see Cross-entity State References). This is because they enable an AMDL expression to distinguish between two entities of the same type when accessing state for those entities.
Using the example above where an event contains a payer and a payee entity, an AMDL expression could access the state of the payee entity using a predicate filter. For example, this rule (written for the 'customer' entity type) would generate an alert for the entity that was the payer of a payment if the state expression PEPFlag
was true for the payee entity:
@alert@eventType("payment")
rules.payeeIsPEP_payerAlert:
state._id == event.payerId&&state.entities.customer[ $._id == event.payeeId
].PEPFlag.single() == true
2.7 Adding State Information to a Rule
A state allows a rule to store information on an event. For example, the state can include information on the number of transactions and the total value over a period. A rule uses information for entity states and global states.
2.7.1 Entity States
Entity states persist against multiple events. For example, you can store the date and time of the first transaction, which is then accessible when processing all future events with that consumer.
Alternatively, you can build a history of all the transaction amounts of a merchant over the past month, and access that information in future events. You can update state variables by values in an event and in other state variables. The fraud system automatically initialises an AMDL the first time it is needed for an entity.
You can specify state variables using an update expression. This type of expression provides a single value that is then used to update that state variable. You can use the value of the state expression to update the state variable on every event.
Every state definition requires a single update expression, but how the value of that expression is stored depends upon the type of the state variable. The default type of a state variable is a single value. The state variable of a single value contains the last value it was updated with, where a new one overwrites it each time the state is updated.
In this example, a rule includes the following state information, where there are no card-present transactions in the last 7 days. The rule also includes an event where there are new card authorisations for a value greater than 250.
@tag(Action = "Decline")
@eventType ("cardRT")
@eventTyoe("cardNRT")
rules.highEcommTxn
(event.msgType.lowercase() == "authorisation" &&
event.msgStatus.lowercase() == "new") &&
(event.amount.baseValue > 250) &&
(state.cardECommerce7d.size(7d) ?? 0) < 1 &&
!event.pointOfServiceContext.cardPresent
You can store a timestamp in an entity state event in the following format:
state.lastEventTime: event.eventTime
This timestamp stores the state for entities of the type this expression is defined for, where AMDL Business Rules expressions are all defined under a specific entity type.
To refer to the stored value of this state expression for the entity of the relevant type in the current event, you can use the scope "state" and the expression name. For example, to refer to the time of the last event for the current entity:
state.lastEventTime
In Business Rules, when an event is being processed, the state is updated after other AMDL expressions have been evaluated. This means that a rule that references state will use the value of the state as it was before the current event was processed. When referenced within another state update, a state variable is accessed as it was before the current event. This is necessary to preserve a well-defined expression evaluation that it is not dependent upon microsecond variations in the processing speed of each rule. However, this does not diminish the computation power of AMDL because the set of prior state plus the event contents comprises the complete known information about that entity.
2.7.2 Global States
A global state expression defines a single variable that is updated by events for any entity of a given type. This ensures that a global state stores information derived from the whole population of entities. One of the main uses of the global state is comparing the activity of one entity with a threshold or comparison value derived from the behaviour of the whole population.
There may be seasonal variations in average transaction values and volumes. Therefore, comparing transaction values to a fixed threshold might generate a much higher volume of false positives. For example, there are periods of increased spending in the run-up to Christmas, Black Friday, or Singles' Day in China.
You are less likely to update a global state as frequently as entity state. Therefore, when referring to a global expression, the value might be up to several seconds out of date. You can also use global states to track rolling averages and similar aggregate values, but not to track values or collections that need to be completely up-to-date at all times. It is highly recommended that all global variables are declared as an aggregate type, for example, a collection (see section Collections) or a rolling average. See the section Using Annotations for a general discussion of this kind of annotation, or @rollingAverage for a detailed description of this specific type of variable.
You define global state expressions in a similar way. For example, to store a rolling average of transaction value across all merchants, you can define this expression under the "merchant" entity type using the @rollingAverage
annotation. For more information on the use of annotations to modify how state is stored, see Using Annotations.
@rollingAverage(24h)
globals.averageAmount: event.amount.baseValue
This annotation, applied to entity or global state variables, keeps a track of the rolling average within a specified time period. You must specify this time period as it cannot keep track of a mean value over all time (because it is implemented as an exponential moving average for performance and storage purposes).
2.8 State Fragmentation and Size Limits
There are several mechanisms built into the event processing components of the system to prevent performance issues due to large amounts of state or global data. These include state fragmentation and limits on the amount of data that can be stored in individual state/global variables, the size of the state for an individual entity, and the total size of global state.
2.8.1 State Fragmentation
State fragmentation is an optional feature that you can enable for specific entity types. Fragmentation allows the fraud engine to break up an entity's state into parts, each of which can be loaded and updated independently. This ensures that the engine does not need to load the entirety of an entity's state when processing an event. State fragmentation results in significant performance benefits for entities with large amounts of state data. State fragments are recombined preiodiacally, and any changes are written to the fraud system datastore.
Fragmentation provides performance benefits when entities of a particular type are likely to have large amounts of stored state. For example, fragmentation exists for an entity type with few unique entities, where each entity occurs in a large proportion of events (such as an entity type like "country" or "merchant category"). Ask your Thredd Account Manager for more information about state fragmentation and how to enable it for the entity types.
Because fragment updates are only recombined periodically, the state for fragmented entities (including all global states), is not guaranteed to be consistent after every event, although it is eventually consistent. For events that occurred close to each other in time, state, global expressions and/or rules that rely on events being processed in strict chronological order may show unexpected behaviour.
Global state is treated as a single global entity that is present in every event, and this entity is always fragmented.
2.8.2 Size Limits
The fraud system sets limits on the size of an individual state variable, and the total size of state stored for an unfragmented and fragmented entity. As a global state is treated as a single fragmented entity, the limits on the total size of state stored for a fragmented entity also apply to a global state.
Each of these types of states has a warning level and a hard limit. If the size exceeds the warning level, an error message is written to the AMDL error log, and a warning icon is displayed in the Rules Management page, next to the relevant expression on the Fraud Transaction Monitoring System. For an individual variable limit, if an entity's state or global state exceeds the warning level, a warning icon does not appear. If the size exceeds the hard limit, no further data is written to the relevant variable, entity, or to the global state. These limits are set to the following default values but can be configured (for details, please contact your Thredd Account Manager).
Type of state |
Type of variable |
Warning level (kB) |
Hard limit (kB) |
---|---|---|---|
Entity state (fragmented or unfragmented) |
Individual variable |
60 |
100 |
Unfragmented state |
Total entity state |
200 |
1000 |
Fragmented state
|
Individual global variable |
100 |
500 |
Total entity state (or total global state across all entity types) |
1024 |
4096 |