In a previous blog post, I wrote about the new Decision Modeling capability introduced in Oracle Process Cloud Service. The blog provided an introduction to DMN and a usage scenario along with a working prototype.
The decision modeling and notation standard released by OMG is a very powerful framework providing an implementation and modeling specification for solving many complex operational and strategic decision in an organization. In this second blog post of the series, I will put the DMN engine in Oracle PCS through a litmus test by implementing a complex decision modeling use case.
To make matters more interesting, I have now selected a decision modelling scenario published as an open challenge in the Decision Management Community in February. The solution shared in this post has been accepted and validated by the community moderator.
The modeling approach shared in this blog is based on the principle of “Inherent Simplicity” which says that every situation, no matter how complex it initially looks, is exceedingly simple. I chose this use case as it shows how principles of decision modeling can allow us to break a layered problem into simpler and easy to implement fragments.
At the end of the post, I will also provide a link to where you can download the sample application. Buckle up, read on and enjoy!
The decision modeling and notation standard released by OMG is a very powerful framework providing an implementation and modeling specification for solving many complex operational and strategic decision in an organization.
Problem Statement
The problem statement was shared on the Decision Management Community website in February 2017 and an abstract of it is presented here:
Your decision model should determine potential fraud during an online product booking process. It’s based on an automatically calculated Fraud Rating Score that should be less than 200 to allow automatic booking. Fraud Rating Score depends on the following factors:
- If Booked Product Type is POST-PAID-HOTEL add 5 to the score
- If Booked Product Type is INTERNAL-FLIGHT add 100 to the score
- If Booked Product Type is INTERNATIONAL-FLIGHT add 25 to the score
- If Booked Product Type is CAR add 10 to the score
- If Booked Product Type is PRE-PAID-HOTEL add 5 to the score
- If there were no previous orders from this customer add 100 to the score
- If Number of Orders from this customer between 1 and 10 including bounds add (100 – Number of Orders * 10) to the score
- If Customer has previous disputes add 190 to the score
Solution
Decision Requirements Diagram
The problem statement can be broken down into different decision elements each producing outcomes which can roll up to provide the final interpretation. Since we are leveraging Decision Modeling and Notation to solve this, the complete solution is presented in form of both a decision model diagram and a decision logic representation.
To evaluate the overall scenario as part of this use case, the overall decision model is broken down into decisions and sub decisions as shown below:
The decision requirements diagram shows how the desired outcome can be achieved by combining modular sub decisions explained here:
- Determine Booking Fraud is the top level decision that asserts a Boolean flag of true|false as a final interpretation of the sub decisions. The flag is based on the Compute Fraud Score decision value (true for fraud score greater than 200 and false for fraud score less than 200 )
- Check Active Disputes is a sub decision that iterates over all Dispute elements of a booking request and if any dispute is valid asserts a constant fraud score (190 in this case)
- Check Past Orders is a sub decision that iterates over all Order elements of a booking request and if there are any past orders, asserts a calculated fraud score (100 – Number of Orders * 10)
- Calculate Product Type Fraud Score is a sub decision that loops through all Products in a booking request and based on the product type, assigns a fraud score. It also rolls up a sum of all assigned fraud score for each product type.
- The Compute Fraud Score sub decision invokes the above sub decisions and sums up the evaluated fraud score from each.
Input Data Definition
In order to implement the decision logic for this scenario, we would need to create a root level Booking request input data type. The data structure for the decision model is depicted below:
- A Booking can have one or more Products. Each product has a unique productId. A product element also has a sub-element representing the productType.
- A Booking can have one or more Orders. Each order has a unique orderId. The bookingState sub element represents if it is a current order or a completed one.
- A Booking can have one or more Disputes. Each dispute has a unique disputetId. The disputeState sub element represents if it is a confirmed or an active dispute. Active disputes are currently under investigation.
Decision Logic Level
As I stated in my previous blog, decision requirements diagram do not convey how the decision is implemented. This is done through decision logic elements. The overall decision model is broken down into individual decisions that are modular with the top level decision determine if the booking is a fraudulent one or not. The sub decisions uses different types of boxed expression to compute a fraud score for every scenario covered in the use case.
I started the solution implementation in Oracle PCS by creating a new Decision Model application. Then added input data elements based on the structure of the Booking element described earlier.
The final implemented decision logic was aligned to the decision requirement diagram. Here is a teaser of the final decision model showing the input data elements and the individual decision logic elements.
The top level decision and each of the underlying decisions is explained in more details in the following section:
Decision 1 – Check Active Disputes
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | If-then-Else |
Decision Input Type | Booking.Disputes[] (List) |
Decision Output Type | Dispute Fraud Score (Integer) |
Question | Does the booking request has any fraud score based on an unresolved disputes? |
Allowed Answers | 190,0 |
The expression simply checks through an If-Then-Else construct if the count of Dispute elements in the Booking request is greater than 0. If a dispute is found (positive number count), then the decision assigns a fraud score of 190 else the fraud score is 0.
Decision 2 – Check Past Disputes
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | If-then-Else |
Decision Input Type | Booking.Orders[] (List) |
Decision Output Type | Dispute Fraud Score (Integer) |
Question | Does the booking request has a fraud score based on an any past orders? |
Allowed Answers | 0-100 |
The conditional expression checks if the count of Order elements in the Booking request is greater than 0. If a previous orders are found (positive number count), then it uses the number of order to determine the fraud score using the below formula.
100 – Number of Orders * 10
The higher the number of previous orders, the lesser is the fraud score. For example, if a booking has 9 previous orders, then the fraud score would be 10 as opposed to a fraud score of 90 if a booking has 1 past order.
Decision 3 – Calculate Product Fraud Score
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | Function with a Decision Table |
Decision Input Type | Product Type (String) |
Decision Output Type | Dispute Fraud Score (integer) |
Question | What is the fraud score for a particular product type? |
Allowed Answers | 0,5,25,100,10,5 |
This is a tricky sub decision to implement. There can be multiple products within a booking request and a fraud score has to assigned based on the product type for each product.
The sub decision is implemented as a function (a boxed expression that creates a parameterized logic to apply multiple times with different parameter values). The function accepts productType as an input and evaluates the fraud score based on a unique hit policy decision table.
Needless to say, this function has to be invoked from another sub decision by passing the appropriate parameter value.
Decision 4 – Loop Through Products
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | Friendly Enough Expression Language (FEEL) |
Decision Input Type | Booking.Products[] (List) |
Decision Output Type | Fraud Score List (integer) |
Question | – |
Allowed Answers | – |
The sub decision is implemented as a friendly enough expression language (FEEL) to loop over the Products in a booking and return a list of fraud score for each product type. This sub decision invokes the parameterized Calculate Product Fraud Score by passing the product type for each product in the loop.
Decision 5 – Compute Fraud Score
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | Friendly Enough Expression Language (FEEL) |
Decision Input Type | Booking |
Decision Output Type | Overall Fraud Score (integer) |
This sub decision is again implemented as a friendly enough expression language (FEEL) to sum all the product scores determined by the previous decisions. It uses a summation function to calculate the sum of all product type fraud score retrieved from the Loop through Product decision and adds the result of the Check Past Orders and Check Active Disputes decisions.
Decision 6 – Determine Booking Fraud
Create a decision in the decision model editor using the configuration option provided here.
Decision Type | Sub Decision |
Boxed Expression Type | If-then-Else |
Decision Input Type | Computed Fraud Score (integer) |
Decision Output Type | Booking Fraud Interpretation (boolean) |
Question | Does the computed fraud score confirm it is a fraudulent booking? |
Answers | True, False |
The conditional expression checks if the value of the computed fraud score is greater than or less than 200. If it is greater than or equal to 200, then it asserts true otherwise false.
This completes the implementation of the decision logic.
Creating a Decision Service
A decision model can expose multiple decision services which in turn are comprised of a combination of decision functions. I created a single decision service with an operation determineBookingFraud by associating the top level decision Determine Booking Fraud to it. After the decision model is deployed to the infrastructure, the decision service is available as a REST endpoint.
Testing the Final Decision Model
The following section shows how the overall solution is unit tested. It also shows how the decision model is exposed as a decision service rest operation which can accept a JSON type request and assert an outcome. But before that, there is another powerful feature in Oracle PCS which allows design time unit testing the decision mode, that I want to talk about.
Unit Testing – Testing for Fraud
Request
Click on the blue arrow icon icon on your decision model to access the unit testing console. This will open a dialog that allows entering input data based on the defined data type. Let us say that for a fraudulent booking scenario, we enter the following data elements:
Response through Sub Decision Chains
When the decision model is executed, all the sub-decisions would execute too. The result for each of the decision functions for the above request through the decision functions would be:
Check Active Disputes | 190 |
Check Past Orders | 90 |
Calculate Product Fraud Score | 5,100 |
Loop Through Products | |
Compute Fraud Score | 385 |
Determine Booking Fraud | true |
Decision Service Testing
The decision model can also be deployed as a service which can be invoked as a REST POST operation (determineBookingFraud) from any external application or process.
Scenario 1 – Non Fraud Scenario
Request
{
"Booking": {
"bookingId": "123213213",
"product":
[
{
"productId": "13213213",
"category": "POST_PAID_HOTEL"
},
{
"productId": "634344",
"category": "INTERNATIONAL_FLIGHT"
}
],
"order":
[
{
"orderId" : "12312214",
"orderType" : "Hardware",
"orderState" : "Completed"
}
],
"Dispute":
[
]
}
}
Response
{
"interpretation": false
}
The total score from the different combinations of products, orders and disputes is:
Products: 5+25=30; Orders: 90; Disputes: 0
Total: 120
The Calculated Fraud Score is 120 which is less than the threshold value of 200 and hence it is not a case of fraud.
Scenario 2 – Fraud Scenario
Request
{
"Booking": {
"bookingId": "123213213",
"product":
[
{
"productId": "asdads",
"category": "POST_PAID_HOTEL"
}
],
"order":
[
{
"orderId": "1232",
"orderType": "New",
"orderState": "Progress"
}
],
"Dispute":
[
{
"disputeId": "123213213",
"disputeState": "Active"
}
]
}
}
Response
{
"interpretation": true
}
The total score from the different combinations of products, orders and disputes in this scenario is:
Products: 5; Orders: 90; Disputes: 190
Total: 285
The Calculated Fraud Score is 285 which is greater than the threshold value of 200 and hence it is a fraud.
Summary
This post covered a glimpse of the true power of decision modeling notation to model and implement real world complex decisions. It also provided a preview of the different types of boxed expressions available in the PCS decision modeling engine and how to create and combine them to create complex decisions.
The sample project can be downloaded from here.
In the previous blog, I explained how to get started with decision modeling and its meta-model through a simple use case. The blog post can be read here:
In the next blog post in this series, I will show how to work with lists and collections in Decision Model through another use case. If you have any comments, suggestions or feedback, please do not hesitate to share it here.