/
45 minute read
September 6, 2023

AMDL Reference

Hidden

ARIC Model Definition Language (AMDL™) is a language used to specify rules and logic within Real-Time Decisioning. For information on how to write business rules and expressions, see Using AMDL. For step-by-step examples, see Tutorial: Defining Rules in Real-Time Decisioning.

Data types

All of the data types that can be used within AMDL can be specified as fixed values. The following are the available data types:

Method Description

Booleans

Example: values.testBool: true

Strings

Example: values.testStr: "foo"

Numbers

Both integer and decimal numbers are permitted by the parser. There is no difference in the way they are handled except when testing strict equality. For more information, see Type coercion in Using AMDL.

Examples:
values.testInt: 50
values.testDec: 50.365

Durations

Durations can be specified as a certain number of days (d), hours (h), minutes (m), or seconds (s). Their main use is for comparison. For instance, you may want to check whether the time between two events is less than one hour.

Examples:
values.days: 5d
values.hours: 2h
values.minutes: 15m
values.seconds: 30s

Sets

Unordered collections of unique values.

Example:
values.allowedStrs: "51","52","53"

Arrays

Ordered collections of values.

Example:
values.array: [3, 1, 4, 1]

Operators

This section details the full list of operators within AMDL and their usage.

Mathematical operators

+ - * /

As well as operating on numbers, + and - can also operate on times and durations. You can add or subtract durations, and add a duration to or subtract a duration from a time.

Examples

Java
Copied

Is this helpful?

Yes
No

String concatenation operator

..

This operator concatenates any two strings, numbers, durations, or times as strings. For non-strings this is done in a format so that they can be coerced back to their original types.

Examples

JSON
Copied

Is this helpful?

Yes
No

Comparison and equality operators

== != < <= > >=

These return a boolean value indicating the result of the comparison. The first two operators can be applied to strings as well as numbers, durations, and times, but the latter four cannot be used for strings.

Operator Description

==

equals

!=

does not equal

<

less than

<=

less than or equal to

>

greater than

>=

greater than or equal to

Examples

Java
Copied

Is this helpful?

Yes
No

Boolean operators

! && ||

Use these operators on boolean values.

Operator Description

!

NOT

&&

AND

| |

OR

Examples

Java
Copied

Is this helpful?

Yes
No

Collection membership operators

~# !#

Use these operators to test membership in a collection and return a boolean value. The left operand must always be some form of collection, and the right operand must be the element of the collection whose membership is being tested.

Operator Description

~#

Contains

!#

Does not contain

Examples

Java
Copied

Is this helpful?

Yes
No

Collection comparison operators

==# !=# <# <=# ># >=#

These operators perform comparison operations on all elements of a collection and return the boolean combination of the results. The left operand must always be a collection and the right operand that which is to be compared.

Examples

Java
Copied

Is this helpful?

Yes
No

Ternary operator

?:

This operator allows one of two operations to be evaluated based on a boolean condition. It is a useful control flow tool to use if, for instance, there are special cases that need action.

Examples

Java
Copied

Is this helpful?

Yes
No

Switch case operator

~?

This operator allows one of many operations to be evaluated based on a switch expression. This is useful if you have several special cases for the same variable, each of which needs a different action.

Case labels must be a fixed value or default. Every switch case must be terminated by a semicolon. Switching based on variable expressions is not supported.

Examples

Java
Copied

Is this helpful?

Yes
No

Default value operator

??

Expression evaluation stops if a referenced variable does not exist. The ?? operator allows a default value to be specified if an expression cannot be evaluated.

Examples

Java
Copied

Is this helpful?

Yes
No

Exists operator

~

This operator checks whether evaluation of a reference returns a non-null value.

Examples

Java
Copied

Is this helpful?

Yes
No

Regular expression match operator

~=

This operator checks whether the left string operand matches the regular expression contained in the right operand. This operator can only be applied to strings. For more information, see Regular expressions in Using AMDL.

Example

Java
Copied

Is this helpful?

Yes
No

Regular expression substitution operator

~:

This operator performs a substitution specified in the right operand on the left string operand. This operator can only be applied to strings. For more information, see Regular expressions in Using AMDL.

Example

Java
Copied

Is this helpful?

Yes
No

Operator precedence

In the table below, all operators are listed in precedence order, from highest to lowest, row by row. Operators in the same row of the table have the same precedence. Each operator is left-associative, right-associative, or non-associative:

  • Left-associative operators of the same precedence bind to the left: e1 op e2 op e3 becomes (e1 op e2) op e3.

  • Right-associative operators of the same precedence bind to the right: e1 op e2 op e3 becomes e1 op (e2 op e3).

  • Non-associative operators do not appear in contexts where their binding is ambiguous.

Operator Associativity
+

( )

Left

[ ]

None

!
~

Right

*

/

Left

+
-
..
~:

Left

>

>=
<
<=

Left

==

!=

Left

Collection operators

Right

&&

Left

||

Left

~?

Right

??

Right

?:

Right

Scope

The following is a list of allowed scopes in AMDL, detailing which are supported in business rules and which are supported in analytical workflows.

  • A scope that supports reference allows you to write expressions that reference something within the scope, used as an operand—for example, event.amount > 100 or lists.negativeList ~# event.card.

  • A scope that supports definition allows you to write expressions that define variables within that scope—for example, rules.rule1: event.amount > 100 or state.example: event.amount.

Scope Business Rules Workflows

Definition

Reference

Definition

Reference

event
Event data fields

rules
Business rules

state
Entity-level profile data

globals
Population-level profile data

values
Static values

var
Transient variables

lists
Data lists

external
External service callouts

models
Model outputs (including risk scores)

param
Workflow parameters

Only in tests

support
Support variables

Only in tests

tests
Unit test expressions

Only in tests

Note
Scope names are reserved keywords within the relevant AMDL implementation—that is, scopes that can be used in business rule AMDL are reserved keywords in business rule expressions, and scopes that can be used in analytical workflows are reserved keywords in workflows. The tests scope is a reserved keyword only in the Expectations panel of a unit test (see Testing analytical workflows in Using AMDL). Reserved keywords cannot be used as the name of a variable of AMDL expression, and references to event data fields with these names must use the square bracket syntax. For more information, see Event data in Using AMDL.

Annotations

This section provides a complete list and descriptions of allowed annotations in AMDL.

@array()

@array(<duration>)
@array(<length>)
@array(duration=<duration>, size=<length>)

This modifies the type of a state expression such that it captures an array, which in the context of AMDL refers to an ordered collection of objects. The size of an array must be limited by specifying a duration (in which case elements older than the specified duration expire and are removed) or a fixed length (in which case the oldest element is removed each time a new element is added, once the array reaches that length) or both (using named arguments, duration and size).

If duration and length limits are both specified, the oldest element is removed if the array reaches its size limit when a new element is added, but elements older than the duration are also removed. A default size limit of 1000 elements is applied to all AMDL collections, including arrays. While this can be overridden by specifying a larger length limit, it is not recommended to do so, as this limit prevents performance issues due to large amounts of state data stored in a single collection.

Java
Copied

Is this helpful?

Yes
No

@comment(<comment>)

Note
This annotation is not available in analytical workflows.

Use this annotation to add comments to an expression.

Java
Copied

Is this helpful?

Yes
No

@defaultValue(<defaultValue>)

Any single value state expression can have a default value applied in the case in which it is referenced but does not yet exist using this annotation. If the state already exists, the default value is not applied.

Java
Copied

Is this helpful?

Yes
No

@eventType(<eventType>)

Note
This annotation is not available in analytical workflows. Each workflow is mapped to one or more event types, so this annotation is not necessary.

A business rule expression accompanied by this annotation is evaluated only for events of the type specified within parentheses. Multiple such annotations can be used to allow evaluation on multiple defined events. If no @eventType annotation is provided for a business rule expression, it is evaluated for all event types by default.

Java
Copied

Is this helpful?

Yes
No

@firstValue()

Any state expression with this annotation is updated only if it does not already exist. It effectively captures the first value to which it is ever evaluated.

Java
Copied

Is this helpful?

Yes
No

@histogram()

@histogram(historyLength=<duration>, bucketSize=<bin width>)
@histogram(historyLength=<duration>, bucketSize=<bin width>, timeField=<time field>)

This changes the type of a state expression to a histogram, which in AMDL refers to collection of accumulated values, bucketed by time. For more information, see Histograms in Using AMDL.

Java
Copied

Is this helpful?

Yes
No

@initialContents(<initialContents>)

Any state expression defined as an array or set can have initial contents, which are elements of the collection defined prior to the state expression being updated for the first time. If the state is referenced but does not exist yet, or when the state is updated for the first time, these values are assigned to the collection before the state expression is evaluated or updated.

Java
Copied

Is this helpful?

Yes
No

@mapOptions(keyDuration=<duration>, keySize=<size>)

When using a state or global expression to define a dynamic map, use this optional annotation to set a limit on the number of keys in the map. Use the keyDuration argument to set a duration limit so that each time the map is updated, keys that were last updated before the specified duration are removed from the map. Use the keySize argument to specify a fixed size limit so that once the number of keys stored in the map reaches this size, each time a new key is added the key that was last updated longest ago is removed. If you use both arguments, keys are removed from the map according to whichever limit is reached first.

JSON
Copied

Is this helpful?

Yes
No

A default size limit of 1000 keys is applied to all maps. While this can be overridden by specifying a larger size limit, it is not recommended to do so, as this can create performance issues due to large amounts of state data stored in a single map. This is particularly relevant for nested maps that store a collection of values with each key. For more information, see Maps in Using AMDL.

@output( )

@output(<namespace>)
@output(mode=ruleoutput)

Note
This annotation is not available in analytical workflows.

This annotation modifies a var expression so that it assigns a tag with the value of that expression for each event for which it is calculated, or outputs the results in the Real-Time Decisioning output. If outputting as a tag, you can provide an optional namespace argument. If it is omitted, the tag generated uses the name of the var expression as its namespace.

JSON
Copied

Is this helpful?

Yes
No

@rollingAverage(<duration>)

This modifies the type of a state expression to a rolling average, which provides the average of all values it is updated with, weighted so that the weight of each historical value decays with time.

JSON
Copied

Is this helpful?

Yes
No

@score(<score>)

Note
This annotation is not available in analytical workflows. For analytical workflows, use an effect to output a risk score.

This annotation enables rules to contribute to the overall risk score of a particular event and entity combination. A rule modified with this annotation adds the score specified in the argument to the risk score output by the businessrules model. This model outputs the total of the scores assigned by all triggered rules.

JSON
Copied

Is this helpful?

Yes
No

@set( )

@set(<duration>)
@set(<length>)
@set(duration=<duration>, size=<length>)

This annotation modifies the type of a state expression such that it captures a set, which in AMDL is an unordered collection of unique objects. Sets must be limited by specifying either a duration (in which case elements older than the specified duration expire and are removed), or a fixed length (in which case the oldest element is removed each time a new unique element is added, once the set reaches that length). If a value that already exists is added to the set, the expiration timer on that element is reset. If duration and length limits are both specified, the oldest element is removed if the set reaches its size limit when a new element is added, but elements older than the duration are also removed. A default size limit of 1000 elements is applied to all AMDL collections, including sets. Although this can be overridden by specifying a larger length limit, it is not recommended, as this limit prevents performance issues due to large amounts of state data stored in a single collection.

JSON
Copied

Is this helpful?

Yes
No

@suppressTag(<namespace>="<tagValue>")

Note
This annotation is not available in analytical workflows. For analytical workflows, use an effect to suppress a tag.

This annotation modifies a rule so that when it triggers for a particular event and entity combination, a particular tag value (specified in the argument to this annotation) is suppressed. The namespace is optional. If no namespace is given, this annotation suppresses the tag with the default namespace and the specified value. This is implemented as part of the implicit rules aggregator step, so applies to tags assigned by rules, models (risk thresholds), and aggregators.

JSON
Copied

Is this helpful?

Yes
No

@tag(<namespace>="<tagValue>")

Note
This annotation is not available in analytical workflows. For analytical workflows, use an effect to add a tag.

This annotation is applicable only to rule expressions. If a rule triggers, the tag is appended to the response. The namespace is an optional argument. If no namespace is given (@tag("<tagValue>")), then it is assigned to the default namespace (_tag). Multiple tag annotations can form part of any rule.

JSON
Copied

Is this helpful?

Yes
No

Methods

Several of the variable types within AMDL have several methods attached to them:

  • String

  • Datetime

  • String similarity

  • Password

  • Compression

  • Number

  • Collection

All of the methods described below are case insensitive (for example, "foo".isblank() and "foo".isBlank() work equivalently).

String

The following methods can be applied to strings. If applied to a type other than a string, the AMDL expression stops evaluation. Implementation of these methods mostly follows the Apache StringUtils class (org.apache.commons.lang3.StringUtils). For details, see StringUtils. Where details are not given here, refer to the StringUtils documentation. Conventions such as lowercase and uppercase are follow the definitions given by the Unicode consortium. For details, see java.lang.Character.

Method Description

String.abbreviate(maxWidth)

Abbreviates the string to be of length less than or equal to the provided maxWidth. If abbreviated, uses ellipses.

rules.alwaysTrue:
"some string".abbreviate(11) == "some string" &&
"some string".abbreviate(7) == "some…​"

String.capitalize()

If the first letter is alphabetical, it is capitalized; otherwise, no change.

rules.alwaysTrue:
"some_string".capitalize() == "Some_string" &&
"1some_string".capitalize() == "1some_string" &&
"Some_string".capitalize() == "Some_string"

String.center(size)

Centers a string inside a larger string of size size, with extra characters being spaces " ".

rules.alwaysTrue:
"some string".center(15) == " some string "

String.charAt(n)

Returns the character at position n in the string (first character is at index 0).

rules.alwaysTrue:
"some string".center(5) == "s"

String.chomp()

Removes one new line from the end of the string if one exists; otherwise, no change.

rules.alwaysTrue:
"some string
".chomp() == "some string".chomp

String.contains(substr)

Checks whether the substring substr is present within the string.

rules.alwaysTrue:
"some string".contains(str) == true &&
"some string".contains(foo) == false

String.containsIgnoreCase(substr)

Checks whether the substring substr is present within the string, irrespective of case.

rules.alwaysTrue:
"some string".containsIgnoreCase(STR) == true &&
"some string".containsIgnoreCase(FOO) == false

String.containsAnyChars(chars)

Checks whether any of the characters in the chars string are present in the string.

rules.alwaysTrue:
"some string".containsAnyChars(sr) == true &&
"some string".containsAnyChars(x1) == false

String.containsNoneChars(chars)

Checks that none of the characters in the chars string are present in the string. Opposite of String.containsanychars(chars).

rules.alwaysTrue:
"some string".containsNoneChars(x1) == true &&
"some string".containsNoneChars(sr) == false

String.countMatches(substr)

Counts how many times the substring substr appears in the string.

rules.alwaysTrue:
"some strange string".countMatches("tr") == 2

String.difference(string2)

Compares the string with string2 and returns the remainder of string2 from the point where the two strings differ.

rules.alwaysTrue:
"some string".difference("something else")
== "thing else" &&
"some string".difference("string") == "tring" &&
"some string".difference("other") == "other"

String.endsWith(suffix)

Checks whether the string ends with the provided suffix.

rules.alwaysTrue:
"some string".endsWith("ing") == true

String.endsWithIgnoreCase(suffix)

Checks whether the string ends with the provided suffix, irrespective of case.

rules.alwaysTrue:
"some string".endsWithIgnoreCase("ING") == true

String.entropy()

Returns the ideal Shannon entropy of the string.

rules.alwaysTrue:
"fooBAR123".entropy() > 1

rules.alwaysTrue:
"foofoofoo".entropy() < "fooBAR123".entropy()

String.equals(str)

Compares the string with the argument string, returning true if they represent identical sequences of characters.

rules.alwaysTrue:
"some string".equals("some string") == true

String.equalsIgnoreCase(str)

Compares the string with the argument string str, returning true if they represent equal sequences of characters, irrespective of case.

rules.alwaysTrue:
"some string".equalsIgnoreCase("Some String") == true

String.format(args)

Requires the string the be a valid format string, then uses the arguments args in the format string according to Java.lang.String.format(). For more on standard Java formatting, see Format String Syntax.

If there are more arguments than format specifiers, the extra arguments are ignored. The number of arguments is variable and may be zero.

rules.alwaysTrue:
"a: %s, b: %s, c: %s".format("example", 1, "???") ==
"a: example, b: 1, c: ???"

String.geodistance(lat1, long1, lat2, long2)

Returns the distance (in km) between two points on the Earth’s surface specified by latitude and longitude (in degrees), where lat1 and long1 are the latitude and longitude of point 1, and lat2 and long2 are the latitude and longitude of point 2. The string that this method operates on is not used—you may simply use an empty string.

rules.alwaysTrue:
"some string".geodistance(90, 0, -90, 0) == 20015.086796020572

String.isAllLowercase()

Checks if the string contains only lowercase letters.

rules.alwaysTrue:
"somestring".isAllLowercase( ) == true &&
"SomeString".isAllLowercase( ) == false &&
"some string".isAllLowercase( ) == false &&
"somestring1".isAllLowercase( ) == false

String.isAllUppercase()

Checks if the string contains only uppercase letters.

rules.alwaysTrue:
"SOMESTRING".isAllUppercase( ) == true &&
"SomeString".isAllUppercase( ) == false &&
"SOME STRING".isAllUppercase( ) == false &&
"SOMESTRING1".isAllUppercase( ) == false

String.isAlpha()

Checks if the string contains only Unicode letters.

rules.alwaysTrue:
"SomeString".isAlpha( ) == true &&
"Some String1".isAlpha( ) == false

String.isAlphanumeric()

Checks if the string contains only Unicode letters or digits.

rules.alwaysTrue:
"SomeString1".isAlphanumeric( ) == true &&
"Some String1".isAlphanumeric( ) == false

String.isAlphanumericSpace()

Checks if the string contains only Unicode letters, digits, or spaces.

rules.alwaysTrue:
"Some String1".isAlphanumericSpace( ) == true &&
"Some String1&".isAlphanumericSpace( ) == false

String.isAlphaSpace()

Checks if the string contains only Unicode letters or spaces.

rules.alwaysTrue:
"Some String".isAlphaSpace() == true &&
"Some String1".isAlpisAlphaSpacehanumericSpace( ) == false

String.isAsciiPrintable()

Checks if the string contains only ASCII printable characters.

rules.alwaysTrue:
"Some ASCII".isAsciiPrintable() == true

String.isBlank()

Checks if the string is whitespace or empty. Unlike StringUtils, null evaluation of the string results in non-evaluation of the rule.

rules.alwaysTrue: "".isBlank() == true &&
" ".isBlank() == false
" some string".isBlank() == false

String.isEmpty()

Checks if the string is empty.

rules.alwaysTrue: "".isempty() == true &&
" ".isempty() == false

String.isNotBlank()

Checks if the string is not empty and not whitespace only. Opposite of String.isblank().

rules.alwaysTrue:
" some string".isnotblank() == true &&
" ".isnotblank() == false &&
"".isnotblank() == false

String.isNotEmpty()

Checks if the string is not empty. Opposite of String.isempty().

rules.alwaysTrue:
" ".isNotEmpty() == true &&
"".isNotEmpty() == false

String.isNumeric()

Checks if the string contains only Unicode digits.

rules.alwaysTrue:
"123456".isNumeric() == true &&
"string123".isNumeric() == false

String.isNumericSpace()

Checks if the string contains only Unicode digits or spaces.

rules.alwaysTrue:
"123 456".isNumericSpace() == true &&
"string 123".isNumericSpace() == false

String.isWhitespace()

Checks if the string contains only whitespace.

rules.alwaysTrue:
"".isWhitespace() == true &&
" ".isWhitespace() == true && "some string".isWhitespace() == false

String.left(len)

Returns the leftmost len characters of the string.

rules.alwaysTrue:
"some string".left(7) == "some st"

String.leftPad(n)

Left pads the string with spaces, up to a total length n.

rules.alwaysTrue:
"abc".leftPad(6) == " abc"

String.length()

Returns the number of characters in the string.

rules.alwaysTrue:
"some_string".length() == 11

String.lowercase()

Converts alphabetical characters in the string to lowercase.

rules.alwaysTrue:
"Mr. Smith".lowercase() == "mr. smith"

String.md5()

Returns the MD5 checksum of the string.

rules.alwaysTrue:
"some str".md5() == "e05679f1d1deca304db99ce2cc19a7c9"

String.ngram(n, accepted_characters)

Implicitly normalizes the string as described in String.normaliseChars(accepted_characters), before returning a collection of possible n-grams contained within the normalized string.

rules.alwaysTrue:
"FOOBAR123".ngram(3,"fba") ~# "fba"

rules.alwaysTrue:
"AbCdEaBcDe".ngram(2,"ace") == "["ac","ce","ea","ac","ce"]"

String.normaliseChars(accepted_characters)

Converts alphabetical characters in the string to lowercase, then removes any that are not in the argument string accepted_characters.

rules.alwaysTrue:
"FOOBAR123".normaliseChars("for") == "foor"

rules.alwaysTrue:
"AbCdEaBcDe".normaliseChars("abd31") == "abd13abd"

String.remove(substr)

Removes all appearances of the substring substr from the string.

rules.alwaysTrue:
"some strange string".remove("tr") == "some strange sing"

String.removeEnd(substr)

Removes substring substr from the end of the string if it appears at the end.

rules.alwaysTrue:
"starting string".removeEnd("ing") == "starting str"

String.removeEndIgnoreCase(substr)

Removes substring substr from the end of the string if it appears at the end, irrespective of case.

rules.alwaysTrue:
"starting string".removeEndIgnoreCase("ING") == "starting str"

String.removePattern(patt)

Removes each substring of the string that matches the given regular expression patt using dotall mode (. matches any character, including line terminators).

rules.alwaysTrue:
"starting string".removePattern("sgi") == "ome trn"

String.removePunctuation()

Removes punctuation characters from the string.

rules.alwaysTrue:
"!some.,punc{tu’ation?".removePunctuation() == "somepunctuation"

String.removeStart(substr)

Removes substring substr from the start of the string if it appears at the start.

rules.alwaysTrue:
"starting string".removeStart("st") == "arting string"

String.removeStartIgnoreCase(substr)

Removes substring substr from the start of the string if it appears at the start, irrespective of case.

rules.alwaysTrue:
"starting string".removeStartIgnoreCase("ST") == "arting string"

String.repeat(n)

Repeats the string n times as in a new string.

rules.alwaysTrue:
"abc".repeat(2) == "abcabc"

String.replace(a, b)

Replaces all occurrences of string a with string b.

rules.alwaysTrue:
"some string".replace("s","5!") == "5!ome 5!tring"

String.replacePattern(pat, rep)

Replaces each substring of the string that matches regular expression pat with the replacement rep using dotall mode (. matches any character, including line terminators).

rules.alwaysTrue:
"some string".replacePattern("ing$","obe") == "some strobe"

String.reverse()

Reverses the order of the characters in the string.

rules.alwaysTrue:
"some string".reverse("abcdefg") == "gfedcba"

String.reverseDelimited(delimiter)

Reverses a string separated by the delimiter delimiter. The strings between the delimiters are not reversed.

rules.alwaysTrue:
"some string".reverseDelimited("a.b.c.d") == "d.c.b.a"

String.right(len)

Returns the rightmost len characters of the string.

rules.alwaysTrue:
"some string".right(4) == "ring"

String.rightPad(n)

Right pads the string with spaces, up to a total length of n.

rules.alwaysTrue:
"abc".rightPad(6) == "abc "

String.sha256()

Returns the SHA-256 hash of the string.

rules.alwaysTrue:
"some str".sha256() == "4ad27ac64e74640fbe5f42e205abdbf30effb67ddcced744ba05d8455cd7eb8a"

String.sequenceProbability(probabilities, accepted_characters)

Given a NxN probability matrix (as a 2D array) and an accepted_characters string of length N, returns the Markov transition probability from the string.

rules.alwaysTrue:
"fooBAR123".sequenceProbability([[0.3,0.7],[0.2,0.4], "fr"]) > 0.1

String.split(delimiter)

Splits the string by the delimiter delimiter into an ordered collection of strings.

rules.alwaysTrue:
"some string".split("st") == ["some ", "ring"]

String.splitByChars(chars)

Splits the string by any of the specified characters chars into an ordered collection of strings.

rules.alwaysTrue:
"some string".splitByChars("si") == ["ome ", "tr", "ng"]

String.splitByCharacterType()

Splits the string by character type into an ordered collection of strings.

rules.alwaysTrue:
"string123!".splitByCharacterType() == ["string", "123, "!"]

String.splitByCharacterTypeCamelCase()

Splits the string by character type (including camel-case words) into an ordered collection of strings.

rules.alwaysTrue:
"SstringString123".splitByCharacterTypeCamelCase() == ["S","String", "String","123"]

String.startsWith(prefix)

Checks whether the string starts with the provided prefix.

rules.alwaysTrue:
"some string".startsWith("som") == true

String.startsWithIgnoreCase(prefix)

Checks whether the string starts with the provided prefix, irrespective of case.

rules.alwaysTrue:
"some string".startsWithIgnoreCase("SO") == true

String.strip()

Removes whitespace from the start and end of the string.

rules.alwaysTrue:
" some string ".strip() == "some string"

String.stripAccents()

Removes diacritics from the string.

rules.alwaysTrue:
"Et ça sera sa moitié".stripAccents() == "Et ca sera sa moitie"

String.stripCharsStart(chars)

Strips any of the provided characters chars from the start of the string.

rules.alwaysTrue:
"some string".stripCharsStart("os") == "me string"

String.stripCharsEnd(chars)

Strips any of the provided characters chars from the end of the string.

rules.alwaysTrue:
"some string".stripCharsEnd("ign") == "some str"

String.substring(start)

Returns the substring after index start.

rules.alwaysTrue:
"abcdefghi".substring(3) == "defghi"

String.substring(start, end)

Returns the substring between indices start and end.

rules.alwaysTrue:
"abcdefghi".substring(3,7) == "defg"

String.substringAfter(sep)

Returns the substring after the first occurrence of the separator sep.

rules.alwaysTrue:
"a.b.c".substringAfter(".") == "b.c"

String.substringAfterLast(sep)

Returns the substring after the last occurrence of the separator sep.

rules.alwaysTrue:
"a.b.c".substringAfterLast(".") == "c"

String.substringBefore(sep)

Returns the substring before the first occurrence of the separator sep.

rules.alwaysTrue:
"a.b.c".substringBefore(".") == "a"

String.substringBeforeLast(sep)

Returns the substring before the last occurrence of the separator sep.

rules.alwaysTrue:
"a.b.c".substringBeforeLast(".") == "a.b"

String.substringBetween(arg1)

Returns the substring nested between the first two instances of arg1.

rules.alwaysTrue:
"abcdefabcdef".substringBetween("ab") == "cdef"

String.substringBetween(arg1, arg2)

Returns the substring nested between the first instances of arg1 and arg2.

rules.alwaysTrue:
"abcdefghi".substringBetween("bc","h") == "defg"

String.swapCase()

Swaps the case of each string character, changing lowercase characters to uppercase and vice versa.

rules.alwaysTrue:
"a string".swapCase() == "A STRING" &&
"A STRING".swapCase() == "a string" &&
"a StRiNg".swapCase() == "A sTrInG"

String.trim()

Removes start and end characters below ASCII code 32 from the string.

rules.alwaysTrue:
"some string ".trim() == "some string"

String.uncapitalize()

If the first letter of the string is alphabetical, it is changed to lowercase; otherwise, no change.

rules.alwaysTrue:
"Some string ".uncapitalize() == "some string"

String.uppercase()

Converts alphabetical characters in the string to lowercase.

rules.alwaysTrue:
"some string ".uppercase() == "SOME STRING"

Datetime

These methods can be used on strings that represent a timestamp. All these methods accept an optional format argument, which defines the format of the string the method is acting on (and any datetime arguments) and how it should be parsed, as well as the format of any datetime output. Without this, ISO-8601 format and UTC are assumed. The format argument can be any of the following:

  • A format string using Java’s DataTimeFormatter syntax. See DateTimeFormatter in the Java documentation for details.

  • iso8601 for ISO-8601 format.

  • epoch for a timestamp expressed as the number of milliseconds since the Unix epoch (midnight UTC on 1st Jan 1970).

  • epochsec for a timestamp expressed as the number of seconds since the Unix epoch.

Method Description

String.isTimeAfter(time)

Returns true if the timestamp string is after the datetime time; otherwise, false.

rules.alwaysTrue:
"2021-01-01T01:00:00Z".isTimeAfter("2021-01-01T00:00:00Z") == true

rules.alwaysTrue:
"2021/01/01 01:00".isTimeAfter("2021/01/01 01:00", "yyyy/MM/dd HH:mm") == true

String.isTimeBefore(time)

Returns true if the timestamp string is before the datetime time; otherwise, false.

rules.alwaysTrue:
"2021-01-01T01:00:00Z".isTimeBefore("2021-01-01T00:30:00Z") == true

rules.alwaysTrue:
"2021/01/01 01:00".isTimeBefore("2021/01/01 00:10", "yyyy/MM/dd HH:mm") == true

String.timeAddMilli(ms)
String.timeAddSec(s)
String.timeAddMin(mins)
String.timeAddHour(hours)
String.timeAddDay(days)

Adds the number of milliseconds, seconds, minutes, hours, or days to the timestamp string.

rules.alwaysTrue:
"2021-01-01T00:00:00Z".timeAddHour(12) == "2021-01-01T12:00:00Z"

rules.alwaysTrue:
"01/01/21 00:00".timeAddDay(10,"dd/MM/yy HH:mm") == "01/11/21 00:00"

String.timeDiffMilli(time)
String.timeDiffSec(time)
String.timeDiffMin(time)
String.timeDiffHour(time)
String.timeDiffDay(time)

Returns the time between the timestamp string and the argument in the units specified, rounded down to the nearest integer.

rules.alwaysTrue:
"2021-01-01T00:00:00Z".timeDiffHour("2021-01-05T12:00:00Z") == 108

rules.alwaysTrue:
"01/01/21 00:00:00".timeDiffSec("01/01/21 00:10:30","dd/MM/yy HH:mm:ss") == "630"

String.timeFormat(format)

Returns the timestamp string, formatted according to the format string specified. This format string has the same possible values as the optional format string that can be added to any of these datetime methods. If a second format string is specified, this represents the format of the timestamp string to be converted.

rules.alwaysTrue:
"2021-04-02T01:23:00Z".timeFormat("yyyy MMM d HH:mm") == "2021 Apr 2 01:23"

rules.alwaysTrue:
"2021/04/02 01:23".timeFormat("utc","yyyy/MM/dd HH:mm") == "2021-04-02T01:23:00Z"

String.timeGetMilli()
String.timeGetSec()
String.timeGetMin()
String.timeGetHour()
String.timeGetDay()

Returns the millisecond, second, minute, hour, or day part of the string timestamp.

rules.alwaysTrue:
"2021-01-01T01:30:25".timeGetHour() == 1

rules.alwaysTrue:
"01:30:25 01 Jan 21".timeGetMin("HH:mm:ss d MMM yy") == 30

String.timeGetField()

Returns any of the standard set of Java temporal fields from the string timestamp. See ChronoField in the Oracle documentation for a list of fields.

rules.alwaysTrue:
"2021-04-02T01:23:45".timeGetField("DAY_OF_YEAR") == 92

rules.alwaysTrue:
"2021/04/02 01:23".timeGetField("DAY_OF_YEAR","yyyy/MM/dd HH:mm") == 92

String.timeNow()

Returns the current time using the format specified by the argument, if an argument is provided, defaulting to ISO-8601. The string operated on has no effect on the return value, so the empty string can be used.

rules.trueOn10thApril2021:
"".timeNow("d MMM yyyy") == 10 Apr 2021

String.timeZoneChange(zone)

Returns the timestamp string, but with the time zone changed to the time zone defined by the zone argument.

rules.alwaysTrue:
"2021-04-02T01:23:00Z".timeZoneChange("+05:00") == "2021-04-02T01:23:00+5:00"

String similarity

Method Description

String.cosineDistance(str)

Returns the cosine distance between the string and str, calculated as 1 - the cosine similarity of the two strings, with each string represented as a set of three shingles (trigrams).

rules.alwaysTrue:
"Some string".cosineDistance("Another string") > 0.5 &&
"Some string".cosineDistance("Some other string") < 0.32

String.cosineDistanceIgnoreCase(str)

Returns the cosine distance between the string and str, ignoring case.

rules.alwaysTrue:
"SOME STRING".cosineDistanceIgnoreCase("Another string") > 0.5 &&
"SOME STRING".cosineDistanceIgnoreCase("Some other string") < 0.32

String.jaccardIndexDistance(str)

Returns the Jaccard index distance between the string and str, calculated as 1 - the Jaccard index for the two strings, with each string represented as a set of three shingles (trigrams).

rules.alwaysTrue:
"Some string".jaccardIndexDistance("Another string") > 0.68 &&
"Some string".jaccardIndexDistance("Some other string") <= 0.5

String.jaccardIndexDistanceIgnoreCase(str)

Returns the Jaccard index distance between the string and str, ignoring case.

rules.alwaysTrue:
"SOME STRING".jaccardIndexDistanceIgnoreCase("Another string") > 0.68 &&
"SOME STRING".jaccardIndexDistanceIgnoreCase("Some other string") <= 0.5

String.jaroWinklerDistance(str)

Returns the Jaro-Winkler distance between the string and str, calculated as 1 - the Jaro-Winkler similarity for the two strings.

rules.alwaysTrue:
"Some string".jaroWinklerDistance("Another string") > 0.25 &&
"Some string".jaroWinklerDistance("Some other string") < 0.25

String.jaroWinklerDistanceIgnoreCase(str)

Returns the Jaro-Winkler distance between the string and str, ignoring case.

rules.alwaysTrue:
"SOME STRING".jaroWinklerDistanceIgnoreCase("Another string") > 0.25 &&
"SOME STRING".jaroWinklerDistanceIgnoreCase("Some other string") < 0.25

String.levenshtein(str)

Returns the Levenshtein distance between the string and str.

rules.alwaysTrue:
"Some String!".levenshtein("same sprung") == 6

String.levenshtein(str,normalised)

If normalised is true, returns the Levenshtein distance between the string and str, normalized to [0-1] by dividing by the length of the longer of the two strings (the maximum possible value of the Levenshtein distance).

rules.alwaysTrue:
"Some String!".levenshtein("same sprung", true) == 0.5

String.levenshteinIgnoreCase(str)

Returns the Levenshtein distance between the string and str, ignoring character case.

rules.alwaysTrue:
"Some String!".levenshteinIgnoreCase("same sprung!") == 0.25

String.levenshteinIgnoreCase(str,normalised)

If normalised is true, returns the Levenshtein distance between the string and str, ignoring character case and normalized to [0-1] as above.

rules.alwaysTrue:
"Some String!".levenshteinIgnoreCase("same sprung", true) == 0.25

String.ratcliffObershelpDistance(str)

Returns the Ratcliff/Obershelp distance between the string and str, calculated as 1 - the Ratcliff/Obershelp similarity of the two strings.

rules.alwaysTrue:
"Some string".ratcliffObershelpDistance("Another string") > 0.25 &&
"Some string".ratcliffObershelpDistance("Some other string") < 0.25

String.ratcliffObershelpDistanceIgnoreCase(str)

Returns the Ratcliff/Obershelp distance between the string and str, ignoring case.

rules.alwaysTrue:
"Some string".ratcliffObershelpDistanceIgnoreCase("Another string") > 0.25 &&
"Some string".ratcliffObershelpDistanceIgnoreCase("Some other string") < 0.25

String.sorensenDiceDistance(str)

Returns the Sørensen-Dice distance between the string and str, calculated as 1 - the Sørensen-Dice coefficient for the two strings, with each string represented as a set of three shingles (trigrams).

rules.alwaysTrue:
"Some string".sorensenDiceDistance("Another string") > 0.5 &&
"Some string".sorensenDiceDistance("Some other string") < 0.35

String.sorensenDiceDistanceIgnoreCase(str)

Returns the Sørensen-Dice distance between the string and str, ignoring case.

rules.alwaysTrue:
"SOME STRING".sorensenDiceDistanceIgnoreCase("Another string") > 0.5 &&
"SOME STRING".sorensenDiceDistanceIgnoreCase("Some other string") < 0.35

Password

Method Description

String.hashPassword()

Returns the PBKDF2 hash of the string. Note that the result of this is different every time.

rules.alwaysTrue:
"mypassword".hashPassword() == "D7CV2UeshEN8C9Lw9U7GVw$q81456B77dNj5DfhUeU10D4FQKR0ZkaV]w_cNN4oUz8"

String.checkPassword(arg)

Validates the supplied password against the hash argument.

rules.alwaysTrue:
"mypassword".checkPassword("D7CV2UeshEN8C9Lw9U7GVw$q81456B77dNj5DfhUeU10D4FQKR0ZkaV]w_cNN4oUz8") == true

Compression

Method Description

String.compress()

Compresses the string using Java Deflator.

rules.alwaysTrue:
"long string […​]".compress() == "y8nPS1coLinkBFLRenp65QA"

String.decompress()

Decompresses the string using Java Deflator.

rules.alwaysTrue:
"y8nPS1coLinkBFLRenp65QA".decompress() == "long string […​]"

Number

The following methods apply to numbers. If the method subject is not a number, expression evaluation halts. Implementation of these methods generally follows the Java Math library. For more information, see Java Math Library.

Method Description

Number.abs()

Returns the absolute value of the number.

rules.alwaysTrue:
-3.abs() == 3

Number.acos()

Returns the arc cosine of the value. The returned angle is in the range 0 - π.

rules.alwaysTrue:
(1).acos() == 0

Number.asin()

Returns the arc sine of the value. The returned angle is in the range - π/2 - π/2.

rules.alwaysTrue:
(0).asin() == 0

Number.atan()

Returns the arc tangent of a value. The returned angle is in the range -π/2 - π/2.

rules.alwaysTrue:
(0).atan() == 0

Number.cbrt()

Returns the cube root of the number.

rules.alwaysTrue:
8.cbrt() == 2

Number.ceil()

Returns the smallest (closest to negative infinity) integer value that is greater than or equal to the number.

rules.alwaysTrue:
2.718.ceil() == 3

Number.cos()

Returns the trigonometric cosine of the value.

rules.alwaysTrue:
0.cos() == 1

Number.cosh()

Returns the hyperbolic cosine of the value.

rules.alwaysTrue:
0.cosh() == 1

Number.exp()

Returns Euler’s number e raised to the power of the subject number.

rules.alwaysTrue:
0.exp() == 1

Number.expm1()

Returns Euler’s number e raised to the power of the subject number minus one.

rules.alwaysTrue:
0.expm1() == 0

Number.floor()

Returns the largest (closest to positive infinity) integer value that is less than or equal to the number.

rules.alwaysTrue:
2.718.floor() == 2

Number.log()

Returns the natural logarithm of the number.

rules.alwaysTrue:
1.log() == 0

Number.log10()

Returns the logarithm (base 10) of the number.

rules.alwaysTrue:
100.log10() == 2

Number.max(n)

Returns the greater of the subject number and the argument n.

rules.alwaysTrue:
8.max(5) == 8

Number.min(n)

Returns the smaller of the subject number and the argument n.

rules.alwaysTrue:
8.min(5) == 5

Number.mod(n)

Returns the remainder when the subject number is divided by the argument n.

rules.alwaysTrue:
27.mod(5) == 2

Number.pow(n)

Raises the number to the power of n.

rules.alwaysTrue:
6.pow(2) == 36

Number.random()

Returns a random number greater than or equal to 0.0 and less than the subject number. Subject number must be positive.

rules.alwaysTrue:
5.random() < 5

Important
Methods such as random() and randomint() that give non-deterministic results should only be used for testing and not in production business rules or workflows. Non-deterministic methods can result in discrepancies between the real-time and asynchronous responses, as the output from the method is different when the event is processed synchronously to produce the real-time response, and when it is processed asynchronously by Real-Time Decisioning.

Number.randomInt()

Returns a random integer greater than or equal to 0 and less than the subject number. Subject number must be positive.

rules.alwaysTrue:
5.randomInt() < 5

Important
Not recommended for use in production (see important note above).

Number.round(n)

Rounds the number to n decimal places. If no argument is specified, rounds to the nearest integer, with ties rounding up. If the number if already specified to less than n decimal places, returns the original number.

rules.alwaysTrue:
2.718.round() == 3

Number.signum()

Returns the signum function of the value, where

Number.signum

Is this helpful?

Yes
No

rules.alwaysTrue:
6.signum() == 1

Number.sin()

Returns the trigonometric sine of the value.

rules.alwaysTrue:
0.sin() == 0

Number.sinh()

Returns the hyperbolic sine of the value.

rules.alwaysTrue:
0.sinh() == 0

Number.sqrt()

Returns the square root of the number.

rules.alwaysTrue:
25.sqrt() == 5

Number.tan()

Returns the trigonometric tangent of the value.

rules.alwaysTrue:
0.tan() == 0

Number.tanh()

Returns the hyperbolic tangent of the value.

rules.alwaysTrue:
0.tanh() == 0

Number.toDegrees()

Converts the number from radians to degrees.

rules.alwaysTrue:
1.57.toDegrees() > 89

Number.toRadians()

Converts the number from degrees to radians.

rules.alwaysTrue:
89.toRadians() > 1.55

Collection

AMDL supports some common collection and statistical methods:

For additional details, see the following Java documentation: CollectionUtils, SummmaryStatistics, and DescriptiveStatistics.

Statistical methods cause expression execution to stop if the collection contains any non-numerical values. In addition, there are some methods that can only be applied to ordered collections.

Common collections

Method Description

Collection.concat(another_collection)

Returns an ordered collection consisting of the original collection with all elements of another_collection appended.

rules.alwaysTrue:
{"method1","method2"}.concat({"method2","method3"}) == ["method1","method2","method2","method3"]

Collection.difference(another_collection)

Returns an unordered collection consisting of all elements in the first collection not present in another_collection.

rules.alwaysTrue:
{"method1","method2"}.difference({"method2","method3"}) == {"method1"}

Collection.intersection(another_collection)

Returns an unordered collection consisting of all elements present in both collections.

rules.alwaysTrue:
{"method1","method2"}.intersection({"method2","method3"}) == {"method2"}

Collection.isEmpty()

Checks whether there are any values in the collection.

rules.alwaysTrue:
["something",'here'].isEmpty() == false

Collection.join(delimiter)

Concatenates all values in the collection into a string. If an argument is provided, it uses this as a delimiter. If no argument is provided, no delimiter is used.

rules.alwaysTrue:
["this","is","a","collection"].join(" ") == "this is a collection" && ["this","is","a","collection"].join() == "thisisacollection"

Collection.single()

For a collection with one element, returns that element as a scalar value. For a collection with more than one element, execution stops.

rules.alwaysTrue:
["Chesney Hawkes"].single() == "Chesney Hawkes"

Collection.size()

Returns the number of elements in the collection.

rules.alwaysTrue:
["this","is","a","collection"].size() == 4

Collection.sorted()

Returns an ordered collection in sorted order. If the values are strings, alphabetical sorting is used. If the values are numbers, numerical sorting is used. For more information, see Ordered collection.

rules.alwaysTrue:
[2,1,3].sorted() == [1,2,3]

Collection.symmetricDifference(another_collection)

Returns an unordered collection consisting of all elements present in the collection and not in another_collection, plus all elements present in another_collection and not the collection.

rules.alwaysTrue:
{"method1","method2"}.symmetricDifference({"method2","method3"}) == ["method1","method3"]

Collection.total()

Returns the sum of the values in the collection. If any non-numeric values are present in the collection, expression execution stops.

rules.alwaysTrue:
[1,3,9].total() == 13

Collection.union(another_collection)

Returns an unordered set consisting of all the unique values in either collection.

rules.alwaysTrue:
{"method1","method2"}.union({"method2","method3"}) == ["method1","method2","method3"]

Statistical collections

Method Description

Collection.geometricMean()

Returns the geometric mean of the values in the collection. If any non-number values are present or the collection is empty, returns null. Note that this does not return an exact amount for integer solutions.

rules.alwaysTrue:
[1,3,9].geometricMean() > 2.9999 &&
[1,3,9].geometricMean() < 3.0001

Collection.kurtosis()

Returns the kurtosis of the values in the collection.

rules.alwaysTrue:
[1,3,9,3,1].kurtosis() > 3.25 &&
[1,3,9,3,1].kurtosis() < 3.26

Collection.max()

Returns the maximum value in the collection.

rules.alwaysTrue:
[1,3,9].max() == 9

Collection.mean()

Returns the arithmetic mean of the values in the collection.

rules.alwaysTrue:
[10,20,30].mean() == 20

Collection.median()

Returns the median of the values in the collection.

rules.alwaysTrue:
[1,2,3,4,1000,2000,3000].median() == 4

Collection.min()

Returns the minimum value in the collection.

rules.alwaysTrue:
[1,3,9].min() == 1

Collection.percentile(p)

Returns an estimate for the pth percentile of the values in the collection.

rules.alwaysTrue:
[1,1,1,1,1,1,1,1,1,2,2,3].percentile(20) == 1

Collection.populationVariance()

Returns the population variance of the values in the collection.

rules.alwaysTrue:
[1,1,4].populationVariance() == 2

Collection.quadraticMean()

Returns the quadratic mean (also known as root-mean-square) of the values in the collection.

rules.alwaysTrue:
[1,3,9].quadraticMean() > 5 &&
[1,3,9].quadraticMean() < 6

Collection.secondMoment()

Returns the second central moment of the values in the collection (the sum of squared deviations from the sample mean).

rules.alwaysTrue:
[1,2,3].secondMoment() > 2

Collection.skewness()

Returns the skewness of the values in the collection, using the following definition:

Skewness

Is this helpful?

Yes
No

where n is the number of elements, xi, in the collection, μ is the mean, and σ is the standard deviation.

Example:
rules.alwaysTrue: [1,3,9,3,1].skewness > 1.73
&& [1,3,9,3,1].skewness < 1.74

Collection.stdDev()

Returns the standard deviation of the values in the collection, based on the sample variance.

Example:
rules.alwaysTrue: [3,4,5].stdDev == 1

Collection.sumOfLogs()

Returns the sum of the natural logs of the values in the collection.

Example:
rules.alwaysTrue: [2.718,2.718,2.718].sumOfLogs > 2.999
&& [2.718,2.718,2.718].sumOfLogs < 3.001

Collection.sumOfSquares()

Returns the sum of the squares of the values in the collection.

Example:
rules.alwaysTrue: [1,3,9].sumOfSquares == 91

Collection.variance()

Returns the (sample) variance of the values in the collection. This method returns the bias-corrected sample variance (using n - 1 in the denominator).

Example:
rules.alwaysTrue: [1,1,4].variance == 3

Ordered collections

Method Description

OrderedCollection.reverse()

Returns the collection in reverse order.

Example:
rules.alwaysTrue: ["a","c","b","d"].reverse == ["a","b","c","d"]

OrderedCollection.shuffle()

Randomly permutes the collection using a default source of randomness.

Example:
rules.alwaysTrue: [["a","b"],["b","a"]] ~# ["a","b"].shuffle

OrderedCollection.sublist(a)

Returns the sublist of all elements with index greater than or equal to the parameter a.

Example:
rules.alwaysTrue: [1,2,3,4,5].sublist(2) == [3,4,5]

OrderedCollection.sublist(a, b)

Returns the sublist of all elements with index greater than or equal to the parameter a and less than the parameter b.

Example:
rules.alwaysTrue: [1,2,3,4,5].sublist(2,4) == [3,4]

Subscribe to our developer newsletter