Creating a Low-Code Decision Intelligence Application

Mike Durran
Oracle Developers
Published in
14 min readJan 13, 2023

--

The use of analytics to assist in decision making is not new, however, the combination of AI/ML, the variety and volume of data, and the availability of augmented analytics software to weave all this together means we’re at a turning point in how we make decisions.

To highlight the current opportunity, the analyst firm Gartner rate decision intelligence as a top strategic trend (2022) and that we are at an innovation point for decision support in the analytics market (David Pidsley, Gartner Market Guide Augmented Analytics, 2022).

In this blog, I’ll describe how I built a composable, low-code decision support application using Oracle Visual Builder, the augmented capabilities of Oracle Analytics, combined with decision modelling in Oracle Integration Services.

Here is a video overview:

Making Bonus Decisions

I’m going to build an application to assist with decisions about annual bonus amount. In general, decisions that are data based lead to more successful outcomes, assuming the data is relevant to the decision being made.

The data available for each employee is analysed using an Oracle Analytics augmented capability called ‘Explain’. This uses ML techniques to determine statistically relevant data factors that may or may not lead to attrition, a factor that may impact on bonus awards.

These factors can then be used to build a decision model in Oracle Integration Services. This model can be tailored in various ways, depending on the various reasons an organisation has for awarding bonuses or not.

I’m not advocating this as a method for awarding bonuses but rather illustrating the technical possibilities using a composable, low-code approach.

Architecture and User Experience

I’m using Visual Builder for it’s low-code approach to application development. There is a web component (oj-oa-project) available in the Visual Builder library that makes it easy to embed Oracle Analytics canvases into a Visual Builder application.

Oracle Integration Services provides decision modelling, with the ability to invoke a model using REST.

The result of an individual decision is stored in Oracle Autonomous Database for review of historical decisions and the ability to store outcomes for subsequent model refinement.

All communication between components uses REST APIs.

This composable, low-code approach, allows the rapid creation of use case specific analytic applications that can be developed in an agile manner and easily modified / refined, reducing costs and reducing the time to a functional application that can improve your business.

Another benefit of this underlying architecture is that it can form the basis of re-usable application ‘templates’ with appropriate Oracle OCI Cloud Services being added or removed as needed.

The planned user experience:

  • User selects an employee from a list
  • Requests a bonus recommendation by invoking an ‘action’ that passes the employees key data points to a decision model
  • Suggested bonus amount is returned to the application
  • User can select a bonus amount from a drop-down that agrees with recommendation or is different
  • User can submit a reason for their decision
  • Historical bonus recommendations are available within the application for additional context when decision making

Building the Decision Model

The Oracle Integration service allows the definition of decision models, based on published standards. At a high level, we determine a central question that we want to answer, in this case, “what bonus amount” to recommend. In order to answer this question, we need to define input parameters and decision logic that relate to that central decision.

But how to determine what the key input parameters are?

Domain expertise is an obvious first consideration but we can also take advantage of machine learning to augment expertise.

The Oracle Analytics augmented Explain functionality provides an analysis of segments that impact the column under investigation within a given data set. This results in a set of columns and values that can form the basis of the decision logic leading to the central decision.

Running Explain on our dataset will give the following results:

In summary, the Explain algorithm has identified a number of columns that have a statistical relevance to whether an employee is likely to leave. For those columns, there are segments that consist of combinations of particular values. It is this information that can be used to generate the decision logic. Here is a closer look at the detailed segments:

An overview Decision Model Diagram is included below:

In this model, each of the columns identified by explain is represented and feeds into the final decision on bonus recommendation. Drilling into these nodes, the following screenshot gives an example of the types of logic that can be defined for each node such as decision tables, if-then-else, functions, expressions and more.

Using the segmentation analysis from Oracle Analytics, each decision node can be defined to return a true / false based on the values identified in the segmentation analysis and the required business priorities leading to the ultimate decision (i.e., in this scenario, does true or false result in higher or lower bonus).

Let’s look at a specific example, for the column ‘Overtime’, the analysis from ‘Explain’ indicates that employees who leave tend to do overtime. This has resulted in a decision point that returns true if the ‘Overtime’ field for an employee is ‘Yes’ and false if it is ‘No’.

Depending on how these individual decision points will impact on the overall bonus recommendation, a decision table is created for combinations of true / false for each column as seen in the table below.

Once the decision model has been completed, it can be exposed using a REST API enabling it to be used within our composable low-code application. The screenshot below shows the endpoint as well as the request and response payload schemas that can be used to send data to the decision model and retrieve a response.

Using the schemas for the request payload and response payload, we can see that an example of the request to the API needs the following fields:

{
"BonusQuery": {
"OverTime": "Yes",
"YearsAtCompany": 270.75,
"EducationField": "Other",
"JobRole": "Research Scientist",
"StockOptionLevel": 10.25
}
}

and the response from the API will take the form:

{
"interpretation": "15%",
"problems": []
}

In the next section, I’ll describe how Oracle Analytics can use this decision model by invoking an event from an embedded analytics canvas that will send a payload containing the values required by the decision model to a VB application and then subsequently pass these to the decision model API and obtain a response consisting of a suggested bonus amount.

Invoking Events in Oracle Analytics

An event can be a user action and software development makes heavy use of event driven programming. Oracle Analytics Data Actions functionality allows the creation of a number of ‘actions’ whereby a user can navigate to different analytics content, passing values as filters, navigate to URLs or call REST APIs. For this use case, I’m going to use an event data action since these allow an end user to invoke the event from within the context of an analytics canvas and pass that context to the host application.

In other words, this allows a user to request a decision model to provide a bonus recommendation.

The UI to create a data action can be found by selecting the menu icon at the top right hand side:

There are a number of options available when creating the event data action as shown below. The type we’re using is ‘Publish Event’:

These types of events are most useful when embedding analytics canvases since while the event is seen by users of the canvas when opened in Oracle Analytics itself, invoking the event has no visual impact until some code is written to listen for the event and handle the event payload.

This is how the event (named ‘Send Event’) appears to a user when they right mouse click over a visualisation:

Creating the Application in Visual Builder

I won’t be going into the details of how to get started with Visual Builder as there are already tutorials available. In this blog, I will describe how to use the cloud services listed earlier to build a low-code decision intelligence application to assist with bonus recommendations.

I’ll start with a basic example of how to use the canvas shown above (used for the event data action example) embedded into a VB application and capture the event payload in the browser console.

I’ve previously covered how to use the Oracle Analytics VB web component. After creating a web application in VB, installing the Oracle Analytics VB web component and referencing that canvas, we get the following:

Handling the Events from Analytics

You will notice that the property panel on the right hand side includes a section ‘Events’. If you click on that section, you will see that ‘no events are defined yet’. In order to define an event, click on the ‘New Event’ button and select ‘New Custom Event’. Expand the section ‘Oracle Analytics Project Events’:

Select the ‘oacEventDataAction’ and choose to create a ‘New Action Chain’. This will create the action chain and the VB UI will switch over to the action chain definition screen. If you switch back to the ‘Page Designer’ and make sure the ‘Oracle Analytics Project’ is in focus, you will see an event has been created in the ‘Events’ section of the component property panel.

Add two input parameters named ‘event’ which is a string and ‘eventPayload’ which is an object. Don’t provide default values.

If you now click in the first field, for the event parameter, select the fx icon that appears to access the expression editor:

For each of these fields, add the following expressions:

$event.detail.event

and

$event.detail.payload.context

Next, create two variables eventNameString of type string and eventNameObject of type object to use with the event that is invoked on the embedded analytics canvas:

Create a function in the JavaScript section of your VB project:

Here is the code for copy / paste:

define([], () => {
'use strict';

class PageModule {

constructor(eventPayloadObject) {
this.eventPayloadObject = eventPayloadObject;
}

outputEvent(eventPayloadObject) {
console.log("***** Payload from DV in Visual Builder ***** ");
console.log("payload = " + JSON.stringify(eventPayloadObject));
console.log("***** Payload from DV n Visual Builder end ***** ");
}

}

return PageModule;
});

If we run the VB application, and display the browser console to view the event payload we see the following:

The event is invoked from the middle item on the bar chart with values of:

Product Category = Office Supplies
Ship Mode = Express Air
Sales = 275,226.82.

Here is the payload in JSON format. You will notice that there are three main sections for each dimension / attribute or measure and the property that contains the actual value is ‘oValueMap’.

payload = {
"ProductCategory": {
"oColumnInfo": {
"_bIsXSA": true,
"SerializedObjectType": {
"Caption": "caption"
},
"_info": {
"columnID": "ProductCategory",
"isTime": false,
"desc": "",
"subjectArea": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"columnHeading": {
"text": "Product Category"
},
"tableHeading": {
"text": "Columns"
},
"type": "regularColumn",
"sqlInfo": {
"dataType": "varchar",
"category": "text",
"primaryType": "text",
"typeName": "VARCHAR",
"aggType": "nonAgg",
"aggRule": "none",
"nullable": true,
"displayFormula": "\"Columns\".\"Product Category\"",
"sqlFormula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Product Category\"",
"sqlFormulaIn2Parts": "\"Columns\".\"Product Category\"",
"sqlFormulaSubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"sqlFormulaDisplaySubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"hasSortKey": false,
"isDoubleColumn": false,
"precision": "",
"scale": ""
},
"formula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Product Category\"",
"additionalProperties": {},
"bIsFormulaValid": true,
"serializedType": "regularColumn",
"isUserExpression": false
},
"_internalIsMeasure": false
},
"oValueMap": {
"Office Supplies": "Office Supplies"
}
},
"ShipMode": {
"oColumnInfo": {
"_bIsXSA": true,
"SerializedObjectType": {
"Caption": "caption"
},
"_info": {
"columnID": "ShipMode",
"isTime": false,
"desc": "",
"subjectArea": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"columnHeading": {
"text": "Ship Mode"
},
"tableHeading": {
"text": "Columns"
},
"type": "regularColumn",
"sqlInfo": {
"dataType": "varchar",
"category": "text",
"primaryType": "text",
"typeName": "VARCHAR",
"aggType": "nonAgg",
"aggRule": "none",
"nullable": true,
"displayFormula": "\"Columns\".\"Ship Mode\"",
"sqlFormula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Ship Mode\"",
"sqlFormulaIn2Parts": "\"Columns\".\"Ship Mode\"",
"sqlFormulaSubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"sqlFormulaDisplaySubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"hasSortKey": false,
"isDoubleColumn": false,
"precision": "",
"scale": ""
},
"formula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Ship Mode\"",
"additionalProperties": {},
"bIsFormulaValid": true,
"serializedType": "regularColumn",
"isUserExpression": false
},
"_internalIsMeasure": false
},
"oValueMap": {
"Express Air": "Express Air"
}
},
"Sales": {
"oColumnInfo": {
"_bIsXSA": true,
"SerializedObjectType": {
"Caption": "caption"
},
"_info": {
"columnID": "Sales",
"isTime": false,
"desc": "",
"subjectArea": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"columnHeading": {
"text": "Sales"
},
"tableHeading": {
"text": "Columns"
},
"type": "regularColumn",
"sqlInfo": {
"dataType": "numeric",
"category": "numeric",
"primaryType": "numeric",
"typeName": "NUMERIC",
"aggType": "agg",
"aggRule": "sum",
"nullable": true,
"displayFormula": "\"Columns\".\"Sales\"",
"sqlFormula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Sales\"",
"sqlFormulaIn2Parts": "\"Columns\".\"Sales\"",
"sqlFormulaSubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"sqlFormulaDisplaySubjectAreaPart": "XSA('mike.durran@oracle.com'.'Sample Order Lines')",
"hasSortKey": false,
"isDoubleColumn": false,
"precision": "0",
"scale": "0"
},
"formula": "XSA('mike.durran@oracle.com'.'Sample Order Lines').\"Columns\".\"Sales\"",
"additionalProperties": {},
"bIsFormulaValid": true,
"serializedType": "regularColumn",
"isUserExpression": false
},
"_internalIsMeasure": true
},
"oValueMap": {
"275226.81999999997": "275,226.81999999995"
}
}
}

The next stage is to create a string that holds the key value (i.e. the dimension / attribute or measure name) and the associated value (from oValueMap).

Here is some sample code for a function that can be called in the action chain that executes after the event is invoked from the embedded analytics canvas.

      createString(eventPayloadObject) {
var res = "";
Object.keys(eventPayloadObject).forEach(function(key) {
console.log(key, eventPayloadObject[key]["oValueMap"]);
res = res.concat(key);
res = res.concat(":");
var temp = eventPayloadObject[key]["oValueMap"];
var temp1 = Object.keys(temp)[0];
res = res.concat(temp1);
res = res.concat(",");
});
console.log(res);
return(res);
}

The resulting string (I’ve called this ‘eventValueString’) is:

ProductCategory:Office Supplies,ShipMode:Express Air,Sales:275226.81999999997,

At this stage, I need to extract the name / value pairs into a payload that can be used with the decision model API. The method I’ve used, makes use of helper functions to define an array (by splitting the string on the ‘“,” character). I then assign each array member to a variable and extract the values from the members of the array by locating the “:” character to form the definition of the payload.

Here are my sample code functions:

      createDecisionInputArray(eventValueString) {
const decisionInputArray = eventValueString.split(",");
return decisionInputArray;
}

extractString(stringToProcess) {
let text = stringToProcess;
let colonLoc = text.indexOf(":");
let stringLen = text.length;
let result = text.substring(colonLoc+1, stringLen);
return(result);
}

extractNumber(stringToProcess) {
let text = stringToProcess;
let colonLoc = text.indexOf(":");
let stringLen = text.length;
let result = Number(text.substring(colonLoc+1, stringLen));
return(result);
}

That was a basic example to explain the concepts we’re going to use to get bonus recommendations. From now on, I’ll refer to the objects that will be used for the bonus application.

Using the approach described, the definition of the payload body that will be sent using the REST call to the decision model API is as follows:

{
"BonusQuery": {
"OverTime": $page.variables.overTimePayload,
"YearsAtCompany": $page.variables.yearsAtCompanyPayload,
"EducationField": $page.variables.educationFieldPayload,
"JobRole": $page.variables.jobRolePayload,
"StockOptionLevel": $page.variables.stockOptionLevelPayload
}
}

I’ve created a suitable canvas in Oracle Analytics that contains these fields and an event data action to allow a payload of values to be passed to the VB application as described earlier in this blog.

Oracle Analytics Canvas to Embed
Event Data Action

The action chain that runs when the event data action is invoked, builds up the payload and then calls the decision model API.

Calling the Decision Model API

In Visual Builder, a reference to a REST API endpoint is defined as a service connection. In order to send REST requests to the decision model endpoint, I create a service connection to the endpoint provided in the decision model services UI by copying that URI and working through the VB UI ‘Define by Endpoint’ option.

If you plan to use token authentication to call the decision model API endpoint, please refer to this documentation reference on that topic.

Decision Model API Response

The response from the decision model API is a recommended bonus amount in the form:

{
"interpretation": "15%",
"problems": []
}

There are many ways that this response could be used, e.g., automatically updating an employee record with the returned bonus percentage or providing a more interactive experience as I’ve chosen to do with the application I’m describing.

The VB action chain allows the API response to be mapped to a variable and a notification fired to let the user know.

My application UI will populate a text box with the suggested bonus amount:

Invoking the event data action and showing the bonus recommendation

The workflow is for the user to then select a bonus amount and provide a narrative that can be used for later reference:

The bonus amount list of values (LOV) is provided by a VB Business Object :

This data is sent to an Oracle Autonomous Database for further analysis and retention of decision history. This is achieved by an ojAction event on the ‘Submit’ button that calls an action chain that assigns the decision and context to a variable that is then sent to the Oracle DB using Oracle REST Data Services (ORDS).

This is the payload used to for the ORDS REST call to input a row into a bonus history decision table:

{
"timestamp": $page.variables.current_timestamp,
"person_id": $page.variables.personIDPayload,
"overtime": $page.variables.overTimePayload,
"years_at_company": $page.variables.yearsAtCompanyPayload,
"education": $page.variables.educationFieldPayload,
"job_role": $page.variables.jobRolePayload,
"stock_option_level": $page.variables.stockOptionLevelPayload,
"bonus_suggestion": $page.variables.bonusDecisionResponse,
"bonus_override": $page.variables.overrideAmount,
"narrative": $page.variables.bonusNarrative
}

A series of visualisations is provided on the right had side of the application that can provide additional context to the end user. These source data from the decisions, recommendations and narratives that are stored in the Oracle DB.

This also provides a mechanism for updating each decision with the outcome after a period of time to further refine future decisions.

Summary

Decision intelligence is at a turning point in the analytics market. Take advantage of this using low-code, composable methods for application creation.

In this blog, I’ve described how to use a number of Oracle cloud services, all generally available today, to build a decision intelligence application to help with the process of awarding bonuses. However, the techniques described can be applicable to any decision making process with modifications to the decision model based on ML analysis of the related data fields using Oracle Analytics Cloud Explain.

--

--

Mike Durran
Oracle Developers

Analytics Product Manager at Oracle. [All content and opinions are my own]