Close
Hyperon as a

Scoring engine

Looking for scoring engine?
Try Hyperon!
Get free proof of concept
Hyperon as a
Scoring engine
Try Hyperon for free
Hyperon Studio
Web UI that lets users to manage their business rules
Hyperon Runtime
Engine embeddable as a lightweight jar
Hyperon REST API
Evaluate parameters or functions via HTTP
Time versioning
Create multiple versions of the business logic and schedule them in a timeline
Contact us

1. Definitions

To start thinking about Hyperon as a scoring engine, we should introduce concepts related to this topic, such as a credit score, scoring model, creditworthiness or FICO score.

1.1. What is a credit score?

When a borrower comes to a lender to take a loan, the lender (bank or credit card company) must evaluate a consumer’s creditworthiness. Depending on available customer data (like payment history or credit types) the lender will make a decision – to offer or deny a credit. In other words – if there is a noticeable risk that a borrower will fail to make required payments, the lender should deny credit application. On the other hand, if the borrower is evaluated to have high creditworthiness, the lender will offer a loan. Thus a borrower’s credit score is simply a number where the higher value translates to higher creditworthiness. A credit score can be used for different financial transactions such as mortgages, private loans, credit cards or even car loans.

1.2. What is a scoring model?

Simply put, a scoring model is a mathematical model which takes many input variables (customer’s data) and converts them all to a single score that represents customer’s creditworthiness. The greater the score, the more likely the borrower will pay required bills. It is common that scoring models come in the form of numerous decision tables that compute partial scores which are then weighted and added together.

1.3. What is a FICO score?

FICO score, introduced by Fair Isaac Corporation, is one of the most widespread scoring model. There are many different versions of this model designed for particular market segments (e.g. automotive lending or mortgage). Even if the exact shape of FICO model is secret, some components are widely known like payment history, current debt, length of credit history, types of credit used or recent loan searches.

2. Hyperon as a Scoring Engine

Now that we have defined basic scoring concepts, we can describe Hyperon as a tool suitable for implementing different scoring models.

2.1. What is a Hyperon?

Hyperon is a Business Rules Management System focused on performance. It is designed to easily handle large decision tables. Hyperon engine uses in-memory indices and carefully designed matching algorithm to search large decision tables (1M rows and more) in few microseconds. Moreover, Hyperon offers a scripting language which allows users to write short functions that expand the capabilities of decision tables. Developers and business experts may modify such functions or tables without touching application’s code. Changes are immediately reflected in any application that uses Hyperon engine.

2.2. Sample scoring model

Suppose we have a scoring model that defines credit score as a weighted sum of partial scores (metrics) for different categories:

final score = w1*s1 + w2*s2 + ... + wn*sn

Each score si is a number from 0 to 100. These components evaluate different aspects of customer’s data, for example:

s1 depends on the ratio of the loan amount requested to the customer’s total income,
s2 depends on the maximum number of days of arrears in the last 12 months,
s3 depends on the average utilization on customer’s credit card accounts in the last 6 months,
s4 depends on the ratio of the current debt of active loans to the customer’s total income,
s5 depends on the number of loan applications in the last 6 months,
s6 depends on the number of active credit accounts,
et cetera.

On the other hand our sample model uses customer’s data which implements the following object model:

Customer
    personal         : PersonalData
    credits          : Credit[]          // all active and closed credits
    totalIncome      : decimal         
    loanRequestsNum  : integer           // num. of loan requests in the last 6 months

Credit
    type             : text              // {auto, mortgage, ...}
    active           : boolean           // whether this credit is active
    value            : decimal
    history          : HistoryEntry[]    // collection of history entries

HistoryEntry
    date            : date
    daysOfArrears   : integer

2.3. Implementing scoring model in Hyperon

To warm up a little we start with implementing the simplest indicator – s5, which depends just on the number of loan requests in the last 6 months. This can be achieved by using Hyperon’s most basic concept called Parameter. Hyperon uses parameters as decision tables to produce outcomes based on the input.

The following is an example of “s5” expressed as a parameter:

Condition
customer.loanRequestNum
Outcome
score
0
100
1 - 2
95
3 - 5
88
*
75

In other words, depending on the customer’s data or context, the “s5” parameter will produce the proper outcome. This parameter can be interpreted as follows:

when the number of loan requests equals to 0 then s5 score is 100,
when the number of loan requests is in [1, 2] then s5 score is 95,
when the number of loan requests is in [3, 5] then s5 score is 88,
for any other input value, the score is 75.

All parameters in Hyperon come in the form of decision tables. They define condition columns and the outcome or multiple outcomes. More on this in a moment.

Let’s take s6 as the second example. This indicator depends on the number of active credit accounts. The collection customer.credits contains all client’s credits, both active and closed, so we will use hyperon function to find the number of active ones.

The following is an example function named util.credits.countActive:

def credits = ctx.get(‘customer.credits’)
def num = 0
for (c in credits) {
if (c.getBoolean(‘active’)) num = num + 1 }

return num

This sample function is implemented in groovy language. It gets all credits from customer’s data, iterates over all of them and counts only those credits which have “active” property set to true.

As groovy is very expressive language the same function can be written with much less keystrokes:

return ctx.get(‘customer.credits’).count { it.getBoolean(‘active’) }

Once we have a dedicated function that counts active credits, we can create a parameter or decision table that takes this function’s result as an input. The following table is an example of “s6” parameter.

Condition
function: util.credits.countActive
Outcome
score
0 - 1
100
2 - 3
98
4 - 6
92
7 - 10
80
*
65

As you can see the previously defined function – named util.credits.countActive – is bound to the condition column which means that Hyperon engine will call this function and get its return value to find the final outcome. For example, if function returns 5, then the outcome of s6 parameter will be 92.

If we need to make s6 indicator dependent on 2 or more conditions, all we have to do is make additional input columns to decision table, like in the following example:

Condition
util. credits. countActive
customer. personal. age
Outcome
score
0 - 1
*
100
2 - 3
0 - 40
98
2 - 3
41 - *
96
4 - 6
0 - 50
92
4 - 6
51 - *
88
...
...
...

3. Hyperon building blocks

To build any solution in Hyperon we can use parameters defined in the form of decision tables and functions written in a scripting language. Now we will shed more light to these core concepts.

3.1. Hyperon parameters

Each Hyperon parameter is a decision table consisting of:

definition of conditions or input columns,
definition of outcomes or output columns,
matrix built from input and output cells,
some meta configuration (matching mode, caching, sorting, etc.).

Each input column (condition) takes a value from some source. There are two types of sources:

value may be a valid path in the domain model (for example: customer.personal.age is a valid path to the number which is the age of this customer),
value may be taken from an outcome of another parameter or function.

Each condition column has defined matcher which is used to check if input value matches to a condition. Hyperon comes with many useful matchers: equals, between, in, not-in, regex, like, contains/all, contains/any, etc.

On the other hand, each output column holds a potential parameter’s value. This potential value will become the outcome if all conditions in the same row evaluate to true.

Hyperon parameters can return a single value, several values (a vector) or even a matrix of values. In combination with different matchers, different matching modes and input sources it is a quite powerful tool in developer’s hands.

The following screenshot presents a real life example of a parameter defined in Hyperon Studio.

Screenshot: Sample parameter

On the above screenshot you can see a parameter that has 6 conditions and 4 outcomes. Conditions include age and the value of the vehicle (between matcher), name of the previous insurer (in matcher) or the insurer’s profile code (default matcher). Hyperon rules engine will find the best matching row and return its 4 output values.

Typically, all Hyperon parameters are fetched from a database and converted into in-memory index when used for the first time. The in-memory index allows to find matching rows in few microseconds. The index structure guarantees O(1) lookups if all conditions use default matchers.

It is not uncommon to see a project with more that 500 parameters (decision tables) with many having more that 100k rows and some larger that 1 million rows.

3.2. Hyperon functions

Although Hyperon decision tables are very powerful means to express business logic, sometimes this may not be enough. For such situations Hyperon offers a scripting language. In other words, developers or business users may write functions which behave exactly the same as decision table do – they consume some inputs and produce some outcome.

Users can write functions in Groovy or JavaScript (whichever they prefer) with help of Hyperon standard library. Functions let them implement any business logic they want.

The following is an example of groovy-based function:

def age = ctx.getNumber( 'client.age' );                // read client's age from model

def factor = 1.8;
if (age > 65) {
 factor = math.log(10, age);
}

def tariff = hyperon.getNumber('tariff', ctx);          // get value from tariff parameter
def baseFee = hyperon.getNumber('base.fee', ctx);       // get value from base.fee parameter

def fee = baseFee * tariff * factor;

return math.round(fee, 2);                              // return fee rounded to 2 digits

Hyperon functions can read domain model, evaluate parameters or call other functions. They can perform any logic dependent on domain model data. Hyperon functions come with standard library in form of predefined objects that enable developers to:

read data from domain model (context),
read parameters,
call other functions,
operate on dates and strings,
perform common math operations,
perform smart type conversions,
write statements to log files,
read hierarchical business configurations.

The following screenshot presents a real-life function edited in Hyperon Studio.

Screenshot: Sample function (script-based business rules)

Functions and parameters together form a coherent ecosystem:

functions can depend on values evaluated from parameters,
parameters can bind functions to condition columns,
parameters can define outcome as a call to a function.

Let’s see how this can be leveraged:

IN
insured.age

$f client.status
OUT
pricing factor
0 - 30
GOLD
3.0
31 - 50
GOLD
$f factor
*
GOLD
$f factor (50)
*
*
4.5

The above parameter:

defines first condition as bound to insured.age from domain model,
defines second condition as bound to value returned by client.status function,
the output column often use literals like: 3.0 or 4.5,
but sometimes it delegates evaluation to function call like: $f factor(50).

Many projects developed for insurance or finance industries have proven that Hyperon parameters and functions together can handle any business logic.

4. Try Hyperon for free

4.1. When to use Hyperon as a BRMS

Hyperon enables developers to externalize complex business logic. This logic (for example  scoring rules) can be modified by developers or business experts in the Hyperon Studio UI. Each modification is immediately reflected in any application that uses Hyperon Runtime library, so we can say users may modify logic on the fly.

This is why Hyperon fits best to rules-heavy projects found often in finance or insurance industries.

4.2. Hyperon key features

Web UI that lets users to manage their business rules
Engine embeddable as a lightweight jar
Evaluate parameters or functions via HTTP
Create multiple versions of the business logic and schedule them in a timeline
Design any domain you want to configure with business logic
Groovy-based scripting language that lets users to extend decision tables
Optional fast persister of domain model data
Monitor the usage of decision tables and DSL scripts or functions
You can import / export configuration from / to Excel

4.3. What's next?

If you’re a programmer
Download Hyperon for free and test run one of our demos available on github and docker
If you’re more into business
Let us prepare for you free proof of concept for your business case using Hyperon
This article was written by Przemek Hertel
Przemek is creator and Chief Architect of Hyperon since 2013. Prior to Hyperon, Przemek designed and implemented SmartParam - open source library allowing lightning-fast querying for parameterized value.
If you like the article, feel free to share it on Facebook, LinkedIn or Twitter.