build.build.openshift.io/travels-1 started
In this example, the following resources were generated in the target
folder in preparation for the binary build:
-
travels-1.0-SNAPSHOT.jar
: Standard JAR file with only the classes and resources of the project. -
travels-1.0-SNAPSHOT-runner.jar
: Executable JAR file for the project. Note that this is not an uber-JAR file because the dependencies are copied into thetarget/lib
directory. -
lib
: Directory with project dependencies.
After the binary build is complete, the result is pushed to the travels
Image Stream that was created by the Kogito Operator and triggers a new deployment.
<IP_ADDRESS>. File build and deployment
You can build and deploy your Kogito services from a single file, such as a Decision Model and Notation (DMN), Business Process Model and Notation (BPMN or BPMN2), Drools Rule Language (DRL), or properties file, or from a directory with multiple files. You can specify a single file from your local file system path or from a Git repository URL, or specify a file directory from a local file system path only. When you upload the file or directory to an OpenShift cluster, a new Source-to-Image (S2I) build is automatically triggered.
| You cannot upload a file directory from a Git repository. The file directory must be in your local file system. However, you can upload single files from either a Git repository or your local file system. |
The following examples upload a single BPMN file from a local directory or Git repository to an OpenShift cluster for an S2I build. These examples are based on the kogito-travel-agency
extended example application.
$ kogito deploy-service travels /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/travels.bpmn2
File found: /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/travels.bpmn2.
...
The requested file(s) was successfully uploaded to OpenShift, a build with this file(s) should now be running. To see the logs, run 'oc logs -f bc/kogito-travel-agency-builder -n kogito'
$ kogito deploy-service travels https://github.com/kiegroup/kogito-examples/blob/stable/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/travels.bpmn2
Asset found: travels.bpmn2.
...
The requested file(s) was successfully uploaded to OpenShift, a build with this file(s) should now be running. To see the logs, run 'oc logs -f bc/kogito-travel-agency-builder -n kogito'
As instructed in the terminal output, you can run the following command to see the build logs:
$ oc logs -f bc/kogito-travel-agency-builder -n kogito
Receiving source from STDIN as file travels.bpmn2
Using docker-registry.default.svc:5000/openshift/kogito-quarkus-ubi8-s2i@sha256:729e158710dedba50a49943ba188d8f31d09568634896de9b903838fc4e34e94 as the s2i builder image
The following examples upload multiple files within a local directory to an OpenShift cluster for an S2I build:
$ kogito deploy-service travels /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels
The provided source is a dir, packing files.
File(s) found: [/tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/flightBooking.bpmn2 /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/hotelBooking.bpmn2 /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/travels.bpmn2].
...
The requested file(s) was successfully uploaded to OpenShift, a build with this file(s) should now be running. To see the logs, run 'oc logs -f bc/travels-builder -n kogito'
For every valid file type (DMN, BPMN, BPMN2, DRL) in the specified directory, the Kogito CLI compresses the files and uploads them to the OpenShift cluster. Any other unsupported file types are not uploaded. To ensure that other file types are uploaded, consider using a source build or a binary build.
If you need to update an uploaded file or directory after you create the build, you can use the oc start-build
command to re-upload the file or directory, as shown in the following example. An S2I build cannot identify only changed files in a directory, so you must re-upload the entire directory of files to update the build.
$ oc start-build kogito-travel-agency-builder --from-file tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels/travels.bpmn2
$ oc start-build kogito-travel-agency-builder --from-dir tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels
If a build fails, use the OpenShift environment variable BUILD_LOGLEVEL
with the desired level as part of your deployment command, as shown in the following example:
$ kogito --verbose deploy-service travels /tmp/kogito-examples/kogito-travel-agency/extended/travels/src/main/resources/org/acme/travels --build-env BUILD_LOGLEVEL=5
<IP_ADDRESS>. Native build and deployment
| Native build and deployment is for Quarkus only and requires GraalVM. |
By default, the Kogito Operator and CLI build services with traditional java
compilers to save time and resources. The final generated artifact is a JAR file for the relevant runtime (defaults to Quarkus) with dependencies in the image user’s home directory, such as /home/kogito/bin/lib
.
However, for Kogito services on Quarkus with GraalVM (required), the Kogito Operator and CLI can build the services in native mode for direct binary execution as native code. Building in native mode uses a very low footprint on the runtime, although many resources are consumed during build time.
For more information about native build performance, see the GraalVM Performance examples for Java.
For more information about ahead-of-time (AOT) compilation, see the GraalVM Native Image documentation.
The following examples build a Kogito service on Quarkus in native mode using the --native
parameter. These examples are based on the kogito-travel-agency
extended example application.
$ cd ~/kogito-travel-agency/extended/travels
$ kogito deploy-service travels --native
$ kogito deploy-service travels https://github.com/kiegroup/kogito-examples/tree/stable/kogito-travel-agency/extended --context-dir travels --native
In Kogito Operator tests, native builds take approximately 10 minutes and the build pod can consume up to 10GB of RAM and 1.5 CPU cores.
By default, a Kogito project does not contain resource requests or limits. As a result, a native build might be terminated due to insufficient memory. To prevent this behavior, you can create a minimum memory request configuration for the Kogito application build, ensuring that the build pod is allocated on an OpenShift node with enough free memory. The side effect of this configuration is that OpenShift prioritizes the build pod.
For more information about OpenShift pod prioritization based on pod requests and limits, see Quality of Service Tiers in the OpenShift documentation.
The following example is a memory request configuration for the kogito-travel-agency
extended example application:
kogito-travel-agency
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoBuild
metadata:
name: travels
namespace: kogito
spec:
type: RemoteSource
gitSource:
contextDir: kogito-travel-agency/extended/travels
uri: "https://github.com/kiegroup/kogito-examples/"
resources:
requests:
memory: "4Gi"
Ensure that you have these resources available on your OpenShift nodes when you run native builds. If the resources are not available, the S2I build fails. You can verify currently allocated and total resources of your nodes by using the command oc describe nodes invoked with admin permission.
|
You can limit the maximum heap space for the JVM used for a native build. You can apply the limitation by setting the quarkus.native.native-image-xmx
property in the application.properties
file of your Kogito project. In this case, the build pod requires roughly -Xmx
plus 2 GB of memory. The -Xmx
value depends on the complexity of the application. For example, for the process-quarkus-example
example application, the -Xmx
value 2g
is sufficient, resulting in the builder pod consuming up to 4.2 GB of memory.
You can also set resource limits for a native build pod. In the process-quarkus-example
application, 80 percent of the memory limit is used for heap space in the JVM responsible for the native build. If the computed heap space limit for the JVM is less than 1024 MB, then all the memory from resource limits is used.
The following example is a memory limit configuration for the process-quarkus-example
example application:
process-quarkus-example
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoBuild
metadata:
name: process-quarkus-example
namespace: kogito
spec:
type: RemoteSource
gitSource:
contextDir: process-quarkus-example
uri: "https://github.com/kiegroup/kogito-examples/"
resources:
limits:
memory: "4Gi"
<IP_ADDRESS>. Kogito service properties configuration
When a Kogito service is deployed, a configMap
resource is created for the application.properties
configuration of the Kogito service.
The name of the configMap
resource consists of the name of the Kogito service and the suffix -properties
, as shown in the following example:
configMap
resource generated during Kogito service deploymentkind: ConfigMap
apiVersion: v1
metadata:
name: kogito-travel-agency-properties
data:
application.properties : |-
property1=value1
property2=value2
The application.properties
data of the configMap
resource is mounted in a volume to the container of the Kogito service. Any runtime properties that you add to the application.properties
section override the default application configuration properties of the Kogito service.
When the application.properties
data of the configMap
is changed, a rolling update modifies the deployment and configuration of the Kogito service.
3.5.6. Kogito Operator interaction with Infinispan
You can install the Infinispan infrastructure for process data persistence in Kogito services by using the following Kogito CLI operation or by providing a KogitoInfra
custom resource definition:
$ kogito install infra INFINISPAN_INFRA_NAME --kind Infinispan --apiVersion infinispan.org/v1 -p PROJECT_NAME
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoInfra
metadata:
name: INFINISPAN_INFRA_NAME
spec:
resource:
apiVersion: infinispan.org/v1
kind: Infinispan
When you install the Infinispan infrastructure for your Kogito project using the Kogito CLI, the Kogito Operator creates a KogitoInfra
custom resource to handle Infinispan deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
The KogitoInfra
resource uses the Infinispan Operator to deploy new Infinispan Server instances when needed. Due to this dependency, the Infinispan Operator must be installed in the same namespace where you deployed the custom Kogito service. For information about Infinispan Operator installation, see the Infinispan Operator Guide.
The Kogito Operator does not manage Infinispan instances, but you can edit and manage Infinispan instances as needed. For example, if you want to scale the Infinispan cluster, you can edit the replicas
field in the infinispan_types.go
custom resource to meet your requirements.
By default, the KogitoInfra
resource creates a secret that holds the user name and password for Infinispan authentication. To view the credentials, enter the following command:
$ oc get secret/kogito-infinispan-credential -o yaml
apiVersion: v1
data:
password: VzNCcW9DeXdpMVdXdlZJZQ==
username: ZGV2ZWxvcGVy
kind: Secret
...
The key values are masked by a Base64 algorithm. To view the password from the previous example output in your terminal, enter the following command:
$ echo VzNCcW9DeXdpMVdXdlZJZQ== | base64 -d
W3BqoCywi1WWvVIe
<IP_ADDRESS>. Infinispan persistence in Kogito services
After you install the KogitoInfra
custom resource to connect with the Infinispan infrastructure, to enable Infinispan persistence for a Kogito service using the Kogito Operator, use the --infra INFINISPAN_INFRA_NAME
flag during deployment in the Kogito CLI or edit the spec.infra
configuration in the KogitoRuntime
custom resource:
$ kogito deploy-service travels --infra INFINISPAN_INFRA_NAME
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoRuntime
metadata:
name: travels
spec:
infra:
- INFINISPAN_INFRA_NAME
If you set up a custom Infinispan cluster, you can refer to it in the KogitoRuntime
custom resource by configuring the following environment variables and application properties:
ENABLE_PERSISTENCE=true
# On Quarkus
QUARKUS_INFINISPAN_CLIENT_AUTH_USERNAME
QUARKUS_INFINISPAN_CLIENT_AUTH_PASSWORD
# On Spring Boot
INFINISPAN_REMOTE_AUTH_USERNAME
INFINISPAN_REMOTE_AUTH_PASSWORD
# On Quarkus
quarkus.infinispan-client.server-list=
quarkus.infinispan-client.use-auth=
quarkus.infinispan-client.sasl-mechanism=
quarkus.infinispan-client.auth-realm=
# On Spring Boot
infinispan.remote.server-list=
infinispan.remote.use-auth=
infinispan.remote.sasl-mechanism=
infinispan.remote.auth-realm=
3.5.7. Kogito Operator interaction with Apache Kafka
You can install the Apache Kafka infrastructure for messaging in Kogito services by using the following Kogito CLI operation or by providing a KogitoInfra
custom resource definition:
$ kogito install infra KAFKA_INFRA_NAME --kind Kafka --apiVersion kafka.strimzi.io/v1beta1 -p PROJECT_NAME
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoInfra
metadata:
name: KAFKA_INFRA_NAME
spec:
resource:
apiVersion: kafka.strimzi.io/v1beta1
kind: Kafka
When you install the Kafka infrastructure for your Kogito project using the Kogito CLI, the Kogito Operator creates a KogitoInfra
custom resource to handle the Kafka cluster deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
The Kogito Operator uses the Strimzi Operator to deploy a Kafka cluster with Zookeeper to support sending and receiving messages within a process. Due to this dependency, the Strimzi Operator must be installed in the Kafka cluster. For information about Strimzi Operator installation, see the Strimzi Quick Start guide.
After the Strimzi Operator deploys Kafka instances, you can edit the instances to meet your requirements.
<IP_ADDRESS>. Apache Kafka messaging in Kogito services
After you install the KogitoInfra
custom resource to connect with the Apache Kafka infrastructure, to enable Kafka messaging for a Kogito service using the Kogito Operator, use the --infra KAFKA_INFRA_NAME
flag during deployment in the Kogito CLI or edit the spec.infra
configuration in the KogitoRuntime
custom resource:
$ kogito deploy-service travels --infra KAFKA_INFRA_NAME
apiVersion: app.kiegroup.org/v1alpha1
kind: KogitoRuntime
metadata:
name: travels
spec:
infra:
- KAFKA_INFRA_NAME
When you enable Kafka messaging, a variable named KAFKA_BOOTSTRAP_SERVERS
is injected into the service container. On Quarkus, this is the default behavior when you use Kafka Client 1.x or later. On Spring Boot, you might need to use a property substitution in the application.properties
file, such as the following example:
spring.kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS}
If the service container has any environment variables with the suffix _BOOTSTRAP_SERVERS
, the variables are also injected by the value of the KAFKA_BOOTSTRAP_SERVERS
variable.
For example, when you deploy the following Kogito service, the variables MP_MESSAGING_INCOMING_TRAVELLERS_BOOTSTRAP_SERVERS
and MP_MESSAGING_OUTGOING_PROCESSEDTRAVELLERS_BOOTSTRAP_SERVERS
are injected with the deployed Kafka service URL:
$ kogito deploy-service travels https://github.com/kiegroup/kogito-examples/tree/stable/kogito-travel-agency/extended --context-dir travels --infra kogito-kafka-infra \
--build-env MAVEN_ARGS_APPEND="-Pevents" \
-e MP_MESSAGING_INCOMING_TRAVELLERS_BOOTSTRAP_SERVERS
-e MP_MESSAGING_OUTGOING_PROCESSEDTRAVELLERS_BOOTSTRAP_SERVERS
If you set up a custom Kafka cluster, you can refer to it in the KogitoRuntime
custom resource by configuring the following environment variable and application property:
ENABLE_EVENTS=true
# On Quarkus
kafka.bootstrap.servers=
# On Spring Boot
spring.kafka.bootstrap-servers=
3.5.8. Kogito Operator interaction with the Kogito Data Index Service
Kogito provides a Data Index Service that stores all Kogito events related to processes, tasks, and domain data. The Data Index Service uses Apache Kafka messaging to consume CloudEvents messages from Kogito services, and then indexes the returned data for future GraphQL queries and stores the data in the Infinispan persistence store. The Data Index Service is at the core of all Kogito search, insight, and management capabilities.
You can use the following Kogito command-line interface (CLI) operation to install the Kogito Data Index Service for data management in Kogito services:
$ kogito install data-index --infra INFINISPAN_INFRA_NAME --infra KAFKA_INFRA_NAME -p PROJECT_NAME
Instead of using the default Infinispan-based persistence in the Kogito Data Index Service, you can use the following command to configure the Data Index Service to use MongoDB persistence storage if needed. A MongoDB Server 3.6 or later must already be installed, configured, and running. For information about MongoDB installation and configuration, see the MongoDB documentation.
$ kogito install data-index --infra KAFKA_INFRA_NAME \
--image quay.io/kiegroup/kogito-data-index-mongodb:latest \
--config quarkus.mongodb.connection-string=MONGODB_SERVER_CONNECTION_STRING \
--config quarkus.mongodb.database=DATABASE_NAME \
--config quarkus.mongodb.credentials.username=USER_NAME \
--config quarkus.mongodb.credentials.password=PASSWORD \
-p PROJECT_NAME
When you enable the Data Index Service for your Kogito project, the Kogito Operator creates a KogitoDataIndex
custom resource to handle the Data Index Service deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
If an Infinispan Server instance and an Apache Kafka cluster are not installed in the OpenShift namespace, you must configure these infrastructure components before installing the Data Index Service:
$ kogito install infra INFINISPAN_INFRA_NAME --kind Infinispan --apiVersion infinispan.org/v1 -p PROJECT_NAME
$ kogito install infra KAFKA_INFRA_NAME --kind Kafka --apiVersion kafka.strimzi.io/v1beta1 -p PROJECT_NAME
<IP_ADDRESS>. Kogito Data Index Service properties configuration
When the Kogito Data Index Service is deployed, a configMap
resource is created for the application.properties
configuration of the Data Index Service.
The name of the configMap
resource consists of the name of the Data Index Service and the suffix -properties
, as shown in the following example:
configMap
resource generated during Kogito Data Index Service deploymentkind: ConfigMap
apiVersion: v1
metadata:
name: data-index-properties
data:
application.properties : |-
property1=value1
property2=value2
The application.properties
data of the configMap
resource is mounted in a volume to the container of the Data Index Service. Any runtime properties that you add to the application.properties
section override the default application configuration properties of the Data Index Service.
When the application.properties
data of the configMap
is changed, a rolling update modifies the deployment and configuration of the Data Index Service.
If your Kogito project uses the infinispan-persistence-addon
add-on to enable Infinispan persistence explicitly, the Kogito Operator mounts a volume based on a configMap
resource created for you during the deployment of the service. This configMap
resource has the -protobuf-files
suffix and lists the protobuf (protocol buffers) files that your service generated during build time.
configMap
resource with protobuf files listedkind: ConfigMap
apiVersion: v1
metadata:
name: example-quarkus-protobuf-files
labels:
kogito-protobuf: true
data:
visaApplications.proto: |-
syntax = "proto2";
package org.acme.travels.visaApplications;
import "kogito-index.proto";
import "kogito-types.proto";
option kogito_model = "VisaApplications";
option kogito_id = "visaApplications";
...
When a new persistent Kogito service is deployed, a new set of protobuf files is generated and the Data Index Service creates a new pod
instance that refers to the new volume.
Updated protobuf files are automatically refreshed by Kubernetes volumes, so if you add a new property in your domain data, this data is reflected automatically in the Data Index Service without restarts.
If a Kogito service is removed, the associated protobuf files are also removed and are no longer visible in the Data Index Service, but the data is still persisted in Infinispan.
3.5.9. Kogito Operator interaction with the Kogito Jobs Service
Kogito provides a Jobs Service for scheduling Business Process Model and Notation (BPMN) process events that are configured to be executed at a specified time. These time-based events in a process model are known as jobs.
By default, Kogito services use an in-memory timer service to handle jobs defined in your BPMN process models. This default timer service does not cover long time intervals and is only suitable for short delays defined in the process. For advanced use cases where time intervals can be days or weeks or when additional event handling options are required, you can configure your Kogito project to use the Kogito Jobs Service as an external timer service.
You can use the following Kogito command-line interface (CLI) operation to install the Kogito Jobs Service for job scheduling in Kogito services:
$ kogito install jobs-service -p PROJECT_NAME
When you enable the Jobs Service for your Kogito project, the Kogito Operator creates a KogitoJobsService
custom resource to handle the Jobs Service deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
<IP_ADDRESS>. Infinispan persistence with the Kogito Jobs Service
To enable Infinispan persistence for the Kogito Jobs Service, you install the Infinispan infrastructure and then you can use the --infra INFINISPAN_INFRA_NAME
flag during deployment in the Kogito CLI or edit the spec.infra
configuration in the KogitoJobsService
custom resource:
$ kogito install infra INFINISPAN_INFRA_NAME --kind Infinispan --apiVersion infinispan.org/v1 -p PROJECT_NAME
$ kogito install jobs-service --infra INFINISPAN_INFRA_NAME
KogitoJobsService
resource with Infinispan persistence enabledapiVersion: app.kiegroup.org/v1alpha1
kind: KogitoJobsService
metadata:
name: jobs-service
spec:
infra:
- kogito-infinispan-infra
build:
envs:
- name: MAVEN_ARGS_APPEND
value: -Ppersistence
You can refine the Infinispan integration by setting the spec.infra
property in the KogitoJobsService
custom resource. With this property set, the Kogito Operator ensures that the Jobs Service has access to the persistence infrastructure configurations.
<IP_ADDRESS>. Kogito Jobs Service properties configuration
When the Kogito Jobs Service is deployed, a configMap
resource is created for the application.properties
configuration of the Jobs Service.
The name of the configMap
resource consists of the name of the Jobs Service and the suffix -properties
, as shown in the following example:
configMap
resource generated during Kogito Jobs Service deploymentkind: ConfigMap
apiVersion: v1
metadata:
name: jobs-service-properties
data:
application.properties : |-
property1=value1
property2=value2
The application.properties
data of the configMap
resource is mounted in a volume to the container of the Jobs Service. Any runtime properties that you add to the application.properties
section override the default application configuration properties of the Jobs Service.
When the application.properties
data of the configMap
is changed, a rolling update modifies the deployment and configuration of the Jobs Service.
3.5.10. Kogito Operator interaction with the Kogito Trusty Service
Kogito provides a Trusty Service that stores all Kogito tracing events related to decisions made in Kogito services. The Trusty Service uses Apache Kafka messaging to consume CloudEvents messages from Kogito services, and then processes the tracing events and stores the data in the Infinispan persistence store.
You can use the following Kogito command-line interface (CLI) operation to install the Kogito Trusty Service for auditing purposes in Kogito services:
$ kogito install trusty --infra INFINISPAN_INFRA_NAME --infra KAFKA_INFRA_NAME -p PROJECT_NAME
To export tracing events from your Kogito project, you must additionally add the tracing-addon
add-on as a dependency to your project.
When you enable the Trusty Service for your Kogito project, the Kogito Operator creates a KogitoTrusty
custom resource to handle the Trusty Service deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
The Kogito Operator uses the Infinispan Operator for persistence infrastructure and the Strimzi Operator for Kafka messaging infrastructure.
If an Infinispan Server instance and an Apache Kafka cluster are not installed in the OpenShift namespace, you must configure these infrastructure components before installing the Trusty Service:
$ kogito install infra INFINISPAN_INFRA_NAME --kind Infinispan --apiVersion infinispan.org/v1 -p PROJECT_NAME
$ kogito install infra KAFKA_INFRA_NAME --kind Kafka --apiVersion kafka.strimzi.io/v1beta1 -p PROJECT_NAME
If the Kogito Explainability Service is enabled, then the Trusty Service also stores the explainability results for all the tracing events.
3.5.11. Kogito Operator interaction with the Kogito Explainability Service
As an aid to the Kogito Trusty Service workflow for storing tracing events, Kogito provides a supplemental Explainability Service that provides an explanation for the decisions made in Kogito services. The Explainability Service uses Apache Kafka messaging to consume CloudEvents messages from the Trusty Service, and then applies explainability algorithms. Some algorithms require the Explainability Service to interact with the Kogito service that evaluated the decision. This communication is performed with HTTP POST
requests.
You can use the following Kogito command-line interface (CLI) operation to install the Kogito Explainability Service for auditing purposes in Kogito services:
$ kogito install explainability --infra KAFKA_INFRA_NAME -p PROJECT_NAME
When you enable the Explainability Service for your Kogito project, the Kogito Operator creates a KogitoExplainability
custom resource to handle the Explainability Service deployment for you. This resource is added to your Kogito project and in the Kogito Operator page of the Installed Operators listed in the OpenShift web console, if applicable.
If an Apache Kafka cluster is not installed in the OpenShift namespace, you must configure this infrastructure component before installing the Explainability Service:
$ kogito install infra KAFKA_INFRA_NAME --kind Kafka --apiVersion kafka.strimzi.io/v1beta1 -p PROJECT_NAME
3.5.12. Kogito Operator interaction with Prometheus
Kogito provides a monitoring-prometheus-addon
add-on that enables Prometheus metrics monitoring for Kogito services. The Kogito Operator uses the Prometheus Operator to expose the metrics from your Kogito project for Prometheus to scrape. Due to this dependency, the Prometheus Operator must be installed in the same namespace as your Kogito project.
When you deploy a Kogito service that uses the monitoring-prometheus-addon
add-on and the Prometheus Operator is installed, the Kogito Operator creates a ServiceMonitor
custom resource to expose the metrics for Prometheus, as shown in the following example:
ServiceMonitor
resource for PrometheusapiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
app: onboarding-service
name: onboarding-service
namespace: kogito
spec:
endpoints:
- path: /metrics
targetPort: 8080
scheme: http
namespaceSelector:
matchNames:
- kogito
selector:
matchLabels:
app: onboarding-service
You must manually configure your Prometheus
custom resource that is managed by the Prometheus Operator to select the ServiceMonitor
resource:
Prometheus
resourceapiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceAccountName: prometheus
serviceMonitorSelector:
matchLabels:
app: onboarding-service
After you configure your Prometheus resource with the ServiceMonitor
resource, you can see the endpoint being scraped by Prometheus in the Targets page in the Prometheus web console:
The metrics exposed by the Kogito service appear in the Graph view:
3.5.13. Deploying Kogito services on Kubernetes
Starting with Kogito 0.11, the Kogito Operator supports Kogito service deployment on Kubernetes. After you create your Kogito services as part of a business application, you can build a container image for your Kogito project, push the image to an image registry, and then use the Kogito Operator to deploy your services on Kubernetes from the registered container image.
The Kogito Operator uses a KogitoRuntime
custom resource that enables Kubernetes or OpenShift deployment from a registered container image. This resource does not require you to build the images in the cluster. Instead, you can pass the Kogito service image that you want to deploy and the Kogito Operator handles the building and deployment for you.
For example Kogito service configurations for a Kubernetes deployment, see the travel-agency
example application for Kubernetes.
-
The Kubernetes command-line tool
kubectl
is installed. For installation instructions, see the Kubernetes documentation. -
Podman container manager is installed. For installation instructions, see the Podman documentation.
-
The application with your Kogito services is in a location that is reachable from your Kubernetes environment.
-
You have Kubernetes permissions to create resources in a specified namespace.
-
Go to the
kogito-cloud-operator
releases page in GitHub, download the latest version of the Kogito OperatorSource code
file, and extract the downloadedkogito-cloud-operator-VERSION
file to a local directory.The Kogito Operator source code contains resources for installing the operator manually for Kubernetes deployments.
-
In a command terminal, navigate to the root of the extracted
kogito-cloud-operator-VERSION
folder and enter the following commands to create the Kubernetes namespace (if not created already) and to install the Kogito Operator in that namespace:Installing the Kogito Operator in a Kubernetes namespace$ cd ~/kogito-cloud-operator-VERSION // Creates the Kubernetes namespace (if not created already) $ export NAMESPACE=kogito $ kubectl create ns $NAMESPACE // Installs the Kogito Operator in the namespace $ ./hack/install.sh
You must be logged in to the relevant Kubernetes cluster using the kubectl
command. For more information about accessing Kubernetes clusters, see the Kubernetes documentation. -
If your Kogito project requires Infinispan persistence and Apache Kafka messaging, install the required Infinispan and Kafka infrastructure components, including the Infinispan Operator and the Strimzi Operator (for Kafka cluster deployment with Zookeeper).
The Kogito Operator cannot automatically install these operators for Infinispan persistence and Kafka messaging, so you must install the components manually, if needed.
For information about Infinispan installation and configuration, see the Infinispan documentation.
For information about Kafka installation and configuration, see the Apache Kafka documentation.
For an example script to install these infrastructure components for Kubernetes, see the
travel-agency
example application for Kubernetes. -
Add the following
quarkus-jvm.Dockerfile
file orspringboot.Dockerfile
file, depending on your framework, to the root of your Kogito project to prepare your project for being built and registered as a container image:On Quarkus:quarkus-jvm.Dockerfile
FROM quay.io/kiegroup/kogito-quarkus-jvm-ubi8:latest COPY target/*-runner.jar $KOGITO_HOME/bin COPY target/lib $KOGITO_HOME/bin/lib COPY target/classes/persistence/ $KOGITO_HOME/data/protobufs
On Spring Boot:springboot.Dockerfile
FROM quay.io/kiegroup/kogito-springboot-ubi8:latest COPY target/*.jar $KOGITO_HOME/bin COPY target/classes/persistence/ $KOGITO_HOME/data/protobufs
-
Build your Kogito project with your preferred method, such as
mvn clean package
. -
Enter the following commands to build the container image, test the image locally, and push the image to the registry using Podman:
Build, test, and push the container image using Podman// Builds the container image
podman build --tag quay.io/NAMESPACE/PROJECT_NAME:latest -f quarkus-jvm.Dockerfile
// Runs the container image locally for testingpodman run --rm -it -p 8080:8080 quay.io/NAME_SPACE/PROJECT_NAME:latest
// Pushes the container image to the Quay registrypodman push quay.io/NAME_SPACE/PROJECT_NAME:latest
-
After you build and push the container image for your Kogito project, create a Kogito service definition YAML file as a
KogitoRuntime
custom resource for your Kogito service, as shown in the following example:Examplekogito-travels.yaml
resource for the Kogito serviceapiVersion: app.kiegroup.org/v1alpha1 kind: KogitoRuntime metadata: name: kogito-travels spec: envs: - name: KOGITO_DATAINDEX_HTTP_URL value: http://data-index.kogito - name: KOGITO_DATAINDEX_WS_URL value: ws://data-index.kogito replicas: 1 image: domain: quay.io/kiegroup/kogito-travels infra: - kogito-kafka-infra - kogito-infinispan-infra
This example is based on the
travel-agency
example application for Kubernetes and includes additional configurations for Infinispan persistence, Kafka messaging, and the Kogito Data Index Service. -
Enter the following command to deploy your Kogito service custom resource to your Kubernetes cluster:
Deploying the Kogito service resource to the Kubernetes clusterkubectl apply -f kogito-travels.yaml
3.5.14. Kogito service deployment troubleshooting
Use the following list to troubleshoot issues that you might encounter when using the Kogito Operator to deploy Kogito services. This list is updated as new issues and workarounds are discovered.
- No builds are running
-
If you do not see any builds running nor any resources created in the relevant namespace, enter the following commands to retrieve running pods and to view the Kogito Operator log for the pod:
View Kogito Operator log for a specified pod// Retrieves running pods $ oc get pods NAME READY STATUS RESTARTS AGE kogito-operator-6d7b6d4466-9ng8t 1/1 Running 0 26m // Opens Kogito Operator log for the pod $ oc logs -f kogito-operator-6d7b6d4466-9ng8t
4. Developing decision services with Kogito
As a developer of business decisions, you can use Kogito business automation to develop decision services using Decision Model and Notation (DMN) models, Drools Rule Language (DRL) rules, XLS or XLSX spreadsheet decision tables, or a combination of all three methods.
4.1. Decision-authoring assets in Kogito
Kogito supports several assets that you can use to define business decisions for your decision service. Each decision-authoring asset has different advantages, and you might prefer to use one or a combination of multiple assets depending on your goals and needs.
The following table highlights the main decision-authoring assets supported in Kogito projects to help you decide or confirm the best method for defining decisions in your decision service.
| Asset | Highlights | Authoring tools | Documentation |
|---|---|---|---|
Decision Model and Notation (DMN) models |
|
Kogito DMN modeler in VSCode or other DMN-compliant editor |
|
DRL rules |
|
Any integrated development environment (IDE) |
|
Spreadsheet decision tables |
|
Spreadsheet editor |
4.2. Example applications with Kogito services
Kogito includes example applications in the kogito-examples
repository in GitHub. These example applications contain various types of Kogito services on Quarkus or Spring Boot to help you develop your own applications. The services use one or more Business Process Model and Notation (BPMN) process models, Decision Model and Notation (DMN) decision models, Drools Rule Language (DRL) rule units, XLS spreadsheet decision tables, or Java classes to define the service logic.
For information about each example application and instructions for using them, see the README
file in the relevant application folder.
In the kogito-examples repository in GitHub, the example applications in the default stable branch use the latest version of Kogito.
|
The following list describes some of the examples provided with Kogito:
- Decision services
-
-
dmn-quarkus-example
anddmn-springboot-example
: A decision service (on Quarkus or Spring Boot) that uses DMN to determine driver penalty and suspension based on traffic violations. -
rules-quarkus-helloworld
: A Hello World decision service on Quarkus with a single DRL rule unit. -
ruleunit-quarkus-example
andruleunit-springboot-example
: A decision service (on Quarkus or Spring Boot) that uses DRL with rule units to validate a loan application and that exposes REST operations to view application status.
-
- Decision services that use the Kogito Trusty Service and Explainability Service
-
-
dmn-tracing-quarkus
: A DMN decision service on Quarkus that uses thetracing-decision-quarkus-addon
add-on to generate tracing events that the Kogito Trusty Service and Explainability Service can consume and expose. -
trusty-demonstration
: A tutorial for deploying thedmn-tracing-quarkus
example application on Kubernetes as a demonstration of Kogito Trusty Service and Explainability Service capabilities in a cloud environment.
-
- Process services
-
-
process-quarkus-example
andprocess-springboot-example
: A process service (on Quarkus or Spring Boot) for ordering items and that exposes REST operations to create new orders or to list and delete active orders. -
onboarding-example
: A combination of a process service and two decision services that use DMN and DRL for onboarding new employees. -
flexible-process-quarkus
andflexible-process-springboot
: A process service (on Quarkus or Spring Boot) that uses flexible processes for case management in Kogito.
-
- Process services that use OptaPlanner
-
-
process-optaplanner-quarkus
andprocess-optaplanner-springboot
: A process service (on Quarkus or Spring Boot) that uses OptaPlanner to optimize airline flight schedules and seat assignments. For information about OptaPlanner integration with Kogito, see the OptaPlanner documentation.
-
- Process services for OpenShift deployment
-
-
kogito-travel-agency
: A combination of process services and decision services that use DRL and XLS for travel booking, intended for deployment on OpenShift.
-
- Serverless Workflow services
-
-
serverless-workflow-greeting-quarkus
andserverless-workflow-greeting-springboot
: A Serverless Workflow greeting service with both JSON and YAML workflow definitions. -
serverless-workflow-service-calls-quarkus
andserverless-workflow-service-calls-springboot
: A Serverless Workflow service for returning country information. -
serverless-workflow-events-quarkus
: A Serverless Workflow service for processing job applicant approvals and that showcases event-driven services.
-
5. Using DMN models in Kogito services
As a developer of business decisions, you can use Decision Model and Notation (DMN) to model a decision service graphically. The decision requirements of a DMN decision model are determined by a decision requirements graph (DRG) that is depicted in one or more decision requirements diagrams (DRDs). A DRD can represent part or all of the overall DRG for the DMN model. DRDs trace business decisions from start to finish, with each decision node using logic defined in DMN boxed expressions such as decision tables.
Kogito provides design and runtime support for DMN 1.2 models at conformance level 3, and runtime-only support for DMN 1.1 and 1.3 models at conformance level 3. You can design your DMN models with the Kogito DMN modeler in VSCode or import existing DMN models into your Kogito projects for deployment and execution. DMN 1.1 and 1.3 models are currently not supported in the Kogito DMN modeler.
For more information about DMN, see the Object Management Group (OMG) Decision Model and Notation specification.
5.1. Decision Model and Notation (DMN)
Decision Model and Notation (DMN) is a standard established by the Object Management Group (OMG) for describing and modeling operational decisions. DMN defines an XML schema that enables DMN models to be shared between DMN-compliant platforms and across organizations so that business analysts and business rules developers can collaborate in designing and implementing DMN decision services. The DMN standard is similar to and can be used together with the Business Process Model and Notation (BPMN) standard for designing and modeling business processes.
For more information about the background and applications of DMN, see the OMG Decision Model and Notation specification.
5.1.1. DMN conformance levels
The DMN specification defines three incremental levels of conformance in a software implementation. A product that claims compliance at one level must also be compliant with any preceding levels. For example, a conformance level 3 implementation must also include the supported components in conformance levels 1 and 2. For the formal definitions of each conformance level, see the OMG Decision Model and Notation specification.
The following list summarizes the three DMN conformance levels:
- Conformance level 1
-
A DMN conformance level 1 implementation supports decision requirement diagrams (DRDs), decision logic, and decision tables, but decision models are not executable. Any language can be used to define the expressions, including natural, unstructured languages.
- Conformance level 2
-
A DMN conformance level 2 implementation includes the requirements in conformance level 1, and supports Simplified Friendly Enough Expression Language (S-FEEL) expressions and fully executable decision models.
- Conformance level 3
-
A DMN conformance level 3 implementation includes the requirements in conformance levels 1 and 2, and supports Friendly Enough Expression Language (FEEL) expressions, the full set of boxed expressions, and fully executable decision models.
Kogito provides design and runtime support for DMN 1.2 models at conformance level 3, and runtime-only support for DMN 1.1 and 1.3 models at conformance level 3. You can design your DMN models with the Kogito DMN modeler in VSCode or import existing DMN models into your Kogito projects for deployment and execution. DMN 1.1 and 1.3 models are currently not supported in the Kogito DMN modeler.
5.1.2. DMN decision requirements diagram (DRD) components
A decision requirements diagram (DRD) is a visual representation of your DMN model. A DRD can represent part or all of the overall decision requirements graph (DRG) for the DMN model. DRDs trace business decisions using decision nodes, business knowledge models, sources of business knowledge, input data, and decision services.
The following table summarizes the components in a DRD:
| Component | Description | Notation | |
|---|---|---|---|
Elements |
Decision |
Node where one or more input elements determine an output based on defined decision logic. |
|
Business knowledge model |
Reusable function with one or more decision elements. Decisions that have the same logic but depend on different sub-input data or sub-decisions use business knowledge models to determine which procedure to follow. |
||
Knowledge source |
External authorities, documents, committees, or policies that regulate a decision or business knowledge model. Knowledge sources are references to real-world factors rather than executable business rules. |
||
Input data |
Information used in a decision node or a business knowledge model. Input data usually includes business-level concepts or objects relevant to the business, such as loan applicant data used in a lending strategy. |
||
Decision service |
Top-level decision containing a set of reusable decisions published as a service for invocation. A decision service can be invoked from an external application or a BPMN business process. |
||
Requirement connectors |
Information requirement |
Connection from an input data node or decision node to another decision node that requires the information. |
|
Knowledge requirement |
Connection from a business knowledge model to a decision node or to another business knowledge model that invokes the decision logic. |
||
Authority requirement |
Connection from an input data node or a decision node to a dependent knowledge source or from a knowledge source to a decision node, business knowledge model, or another knowledge source. |
||
Artifacts |
Text annotation |
Explanatory note associated with an input data node, decision node, business knowledge model, or knowledge source. |
|
Association |
Connection from an input data node, decision node, business knowledge model, or knowledge source to a text annotation. |
The following table summarizes the permitted connectors between DRD elements:
| Starts from | Connects to | Connection type | Example |
|---|---|---|---|
Decision |
Decision |
Information requirement |
|
Business knowledge model |
Decision |
Knowledge requirement |
|
Business knowledge model |
|||
Decision service |
Decision |
Knowledge requirement |
|
Business knowledge model |
|||
Input data |
Decision |
Information requirement |
|
Knowledge source |
Authority requirement |
||
Knowledge source |
Decision |
Authority requirement |
|
Business knowledge model |
|||
Knowledge source |
|||
Decision |
Text annotation |
Association |
|
Business knowledge model |
|||
Knowledge source |
|||
Input data |
The following example DRD illustrates some of these DMN components in practice:
The following example DRD illustrates DMN components that are part of a reusable decision service:
In a DMN decision service node, the decision nodes in the bottom segment incorporate input data from outside of the decision service to arrive at a final decision in the top segment of the decision service node. The resulting top-level decisions from the decision service are then implemented in any subsequent decisions or business knowledge requirements of the DMN model. You can reuse DMN decision services in other DMN models to apply the same decision logic with different input data and different outgoing connections.
5.1.3. Rule expressions in FEEL
Friendly Enough Expression Language (FEEL) is an expression language defined by the Object Management Group (OMG) DMN specification. FEEL expressions define the logic of a decision in a DMN model. FEEL is designed to facilitate both decision modeling and execution by assigning semantics to the decision model constructs. FEEL expressions in decision requirements diagrams (DRDs) occupy table cells in boxed expressions for decision nodes and business knowledge models.
For more information about FEEL in DMN, see the OMG Decision Model and Notation specification.
<IP_ADDRESS>. Data types in FEEL
Friendly Enough Expression Language (FEEL) supports the following data types:
-
Numbers
-
Strings
-
Boolean values
-
Dates
-
Time
-
Date and time
-
Days and time duration
-
Years and months duration
-
Functions
-
Contexts
-
Ranges (or intervals)
-
Lists
The DMN specification currently does not provide an explicit way of declaring a variable as a function , context , range , or list , but Kogito extends the DMN built-in types to support variables of these types.
|
The following list describes each data type:
- Numbers
-
Numbers in FEEL are based on the IEEE 754-2008 Decimal 128 format, with 34 digits of precision. Internally, numbers are represented in Java as
BigDecimals
withMathContext DECIMAL128
. FEEL supports only one number data type, so the same type is used to represent both integers and floating point numbers.FEEL numbers use a dot (
.
) as a decimal separator. FEEL does not support-INF
,+INF
, orNaN
. FEEL usesnull
to represent invalid numbers.Kogito extends the DMN specification and supports additional number notations:
-
Scientific: You can use scientific notation with the suffix
e<exp>
orE<exp>
. For example,1.2e3
is the same as writing the expression1.2*10**3
, but is a literal instead of an expression. -
Hexadecimal: You can use hexadecimal numbers with the prefix
0x
. For example,0xff
is the same as the decimal number255
. Both uppercase and lowercase letters are supported. For example,0XFF
is the same as0xff
. -
Type suffixes: You can use the type suffixes
f
,F
,d
,D
,l
, andL
. These suffixes are ignored.
-
- Strings
-
Strings in FEEL are any sequence of characters delimited by double quotation marks.
Example"John Doe"
- Boolean values
-
FEEL uses three-valued boolean logic, so a boolean logic expression may have values
true
,false
, ornull
. - Dates
-
Date literals are not supported in FEEL, but you can use the built-in
date()
function to construct date values. Date strings in FEEL follow the format defined in the XML Schema Part 2: Datatypes document. The format is"YYYY-MM-DD"
whereYYYY
is the year with four digits,MM
is the number of the month with two digits, andDD
is the number of the day.Example:
date( "2017-06-23" )
Date objects have time equal to
"00:00:00"
, which is midnight. The dates are considered to be local, without a timezone. - Time
-
Time literals are not supported in FEEL, but you can use the built-in
time()
function to construct time values. Time strings in FEEL follow the format defined in the XML Schema Part 2: Datatypes document. The format is"hh:mm:ss[.uuu][(+-)hh:mm]"
wherehh
is the hour of the day (from00
to23
),mm
is the minutes in the hour, andss
is the number of seconds in the minute. Optionally, the string may define the number of milliseconds (uuu
) within the second and contain a positive (+
) or negative (-
) offset from UTC time to define its timezone. Instead of using an offset, you can use the letterz
to represent the UTC time, which is the same as an offset of-00:00
. If no offset is defined, the time is considered to be local.Examples:
time( "04:25:12" ) time( "14:10:00+02:00" ) time( "22:35:40.345-05:00" ) time( "15:00:30z" )
Time values that define an offset or a timezone cannot be compared to local times that do not define an offset or a timezone.
- Date and time
-
Date and time literals are not supported in FEEL, but you can use the built-in
date and time()
function to construct date and time values. Date and time strings in FEEL follow the format defined in the XML Schema Part 2: Datatypes document. The format is"<date>T<time>"
, where<date>
and<time>
follow the prescribed XML schema formatting, conjoined byT
.Examples:
date and time( "2017-10-22T23:59:00" ) date and time( "2017-06-13T14:10:00+02:00" ) date and time( "2017-02-05T22:35:40.345-05:00" ) date and time( "2017-06-13T15:00:30z" )
Date and time values that define an offset or a timezone cannot be compared to local date and time values that do not define an offset or a timezone.
If your implementation of the DMN specification does not support spaces in the XML schema, use the keyword dateTime
as a synonym ofdate and time
. - Days and time duration
-
Days and time duration literals are not supported in FEEL, but you can use the built-in
duration()
function to construct days and time duration values. Days and time duration strings in FEEL follow the format defined in the XML Schema Part 2: Datatypes document, but are restricted to only days, hours, minutes and seconds. Months and years are not supported.Examples:
duration( "P1DT23H12M30S" ) duration( "P23D" ) duration( "PT12H" ) duration( "PT35M" )
If your implementation of the DMN specification does not support spaces in the XML schema, use the keyword dayTimeDuration
as a synonym ofdays and time duration
. - Years and months duration
-
Years and months duration literals are not supported in FEEL, but you can use the built-in
duration()
function to construct days and time duration values. Years and months duration strings in FEEL follow the format defined in the XML Schema Part 2: Datatypes document, but are restricted to only years and months. Days, hours, minutes, or seconds are not supported.Examples:
duration( "P3Y5M" ) duration( "P2Y" ) duration( "P10M" ) duration( "P25M" )
If your implementation of the DMN specification does not support spaces in the XML schema, use the keyword yearMonthDuration
as a synonym ofyears and months duration
. - Functions
-
FEEL has
function
literals (or anonymous functions) that you can use to create functions. The DMN specification currently does not provide an explicit way of declaring a variable as afunction
, but Kogito extends the DMN built-in types to support variables of functions.Example:
function(a, b) a + b
In this example, the FEEL expression creates a function that adds the parameters
a
andb
and returns the result. - Contexts
-
FEEL has
context
literals that you can use to create contexts. Acontext
in FEEL is a list of key and value pairs, similar to maps in languages like Java. The DMN specification currently does not provide an explicit way of declaring a variable as acontext
, but Kogito extends the DMN built-in types to support variables of contexts.Example:
{ x : 5, y : 3 }
In this example, the expression creates a context with two entries,
x
andy
, representing a coordinate in a chart.In DMN 1.2, another way to create contexts is to create an item definition that contains the list of keys as attributes, and then declare the variable as having that item definition type.
The Kogito DMN API supports DMN
ItemDefinition
structural types in aDMNContext
represented in two ways:-
User-defined Java type: Must be a valid JavaBeans object defining properties and getters for each of the components in the DMN
ItemDefinition
. If necessary, you can also use the@FEELProperty
annotation for those getters representing a component name which would result in an invalid Java identifier. -
java.util.Map
interface: The map needs to define the appropriate entries, with the keys corresponding to the component name in the DMNItemDefinition
.
-
- Ranges (or intervals)
-
FEEL has
range
literals that you can use to create ranges or intervals. Arange
in FEEL is a value that defines a lower and an upper bound, where either can be open or closed. The DMN specification currently does not provide an explicit way of declaring a variable as arange
, but Kogito extends the DMN built-in types to support variables of ranges.The syntax of a range is defined in the following formats:
range := interval_start endpoint '..' endpoint interval_end interval_start := open_start | closed_start open_start := '(' | ']' closed_start := '[' interval_end := open_end | closed_end open_end := ')' | '[' closed_end := ']' endpoint := expression
The expression for the endpoint must return a comparable value, and the lower bound endpoint must be lower than the upper bound endpoint.
For example, the following literal expression defines an interval between
1
and10
, including the boundaries (a closed interval on both endpoints):[ 1 .. 10 ]
The following literal expression defines an interval between 1 hour and 12 hours, including the lower boundary (a closed interval), but excluding the upper boundary (an open interval):
[ duration("PT1H") .. duration("PT12H") )
You can use ranges in decision tables to test for ranges of values, or use ranges in simple literal expressions. For example, the following literal expression returns
true
if the value of a variablex
is between0
and100
:x in [ 1 .. 100 ]
- Lists
-
FEEL has
list
literals that you can use to create lists of items. Alist
in FEEL is represented by a comma-separated list of values enclosed in square brackets. The DMN specification currently does not provide an explicit way of declaring a variable as alist
, but Kogito extends the DMN built-in types to support variables of lists.Example:
[ 2, 3, 4, 5 ]
All lists in FEEL contain elements of the same type and are immutable. Elements in a list can be accessed by index, where the first element is
1
. Negative indexes can access elements starting from the end of the list so that-1
is the last element.For example, the following expression returns the second element of a list
x
:x[2]
The following expression returns the second-to-last element of a list
x
:x[-2]
Elements in a list can also be counted by the function
count
, which uses the list of elements as the parameter.For example, the following expression returns
4
:count([ 2, 3, 4, 5 ])
<IP_ADDRESS>. Built-in functions in FEEL
To promote interoperability with other platforms and systems, Friendly Enough Expression Language (FEEL) includes a library of built-in functions. The built-in FEEL functions are implemented in the Drools Decision Model and Notation (DMN) engine so that you can use the functions in your DMN decision services.
The following sections describe each built-in FEEL function, listed in the format NAME( PARAMETERS )
. For more information about FEEL functions in DMN, see the OMG Decision Model and Notation specification.
Conversion functions
The following functions support conversion between values of different types. Some of these functions use specific string formats, such as the following examples:
-
date string
: Follows the format defined in the XML Schema Part 2: Datatypes document, such as2020-06-01
-
time string
: Follows one of the following formats:-
Format defined in the XML Schema Part 2: Datatypes document, such as
23:59:00z
-
Format for a local time defined by ISO 8601 followed by
@
and an IANA Timezone, such as00:01:00@Etc/UTC
-
-
date time string
: Follows the format of adate string
followed byT
and atime string
, such as2012-12-25T11:00:00Z
-
duration string
: Follows the format ofdays and time duration
andyears and months duration
defined in the XQuery 1.0 and XPath 2.0 Data Model, such asP1Y2M
- date( from ) - using date
-
Converts
from
to adate
value.Table 5. Parameters Parameter Type Format from
string
date string
Exampledate( "2012-12-25" ) - date( "2012-12-24" ) = duration( "P1D" )
- date( from ) - using date and time
-
Converts
from
to adate
value and sets time components to null.Table 6. Parameters Parameter Type from
date and time
Exampledate(date and time( "2012-12-25T11:00:00Z" )) = date( "2012-12-25" )
- date( year, month, day )
-
Produces a
date
from the specified year, month, and day values.Table 7. Parameters Parameter Type year
number
month
number
day
number
Exampledate( 2012, 12, 25 ) = date( "2012-12-25" )
- date and time( date, time )
-
Produces a
date and time
from the specified date and ignores any time components and the specified time.Table 8. Parameters Parameter Type date
date
ordate and time
time
time
Exampledate and time ( "2012-12-24T23:59:00" ) = date and time(date( "2012-12-24" ), time( "23:59:00" ))
- date and time( from )
-
Produces a
date and time
from the specified string.Table 9. Parameters Parameter Type Format from
string
date time string
Exampledate and time( "2012-12-24T23:59:00" ) + duration( "PT1M" ) = date and time( "2012-12-25T00:00:00" )
- time( from )
-
Produces a
time
from the specified string.Table 10. Parameters Parameter Type Format from
string
time string
Exampletime( "23:59:00z" ) + duration( "PT2M" ) = time( "00:01:00@Etc/UTC" )
- time( from )
-
Produces a
time
from the specified parameter and ignores any date components.Table 11. Parameters Parameter Type from
time
ordate and time
Exampletime(date and time( "2012-12-25T11:00:00Z" )) = time( "11:00:00Z" )
- time( hour, minute, second, offset? )
-
Produces a
time
from the specified hour, minute, and second component values.Table 12. Parameters Parameter Type hour
number
minute
number
second
number
offset
(Optional)days and time duration
or nullExampletime( "23:59:00z" ) = time(23, 59, 0, duration( "PT0H" ))
- number( from, grouping separator, decimal separator )
-
Converts
from
to anumber
using the specified separators.Table 13. Parameters Parameter Type from
string
representing a valid numbergrouping separator
Space ( ), comma (
,
), period (.
), or nulldecimal separator
Same types as
grouping separator
, but the values cannot matchExamplenumber( "1 000,0", " ", "," ) = number( "1,000.0", ",", "." )
- string( from )
-
Provides a string representation of the specified parameter.
Table 14. Parameters Parameter Type from
Non-null value
Examplesstring( 1.1 ) = "1.1" string( null ) = null
- duration( from )
-
Converts
from
to adays and time duration
value oryears and months duration
value.Table 15. Parameters Parameter Type Format from
string
duration string
Examplesdate and time( "2012-12-24T23:59:00" ) - date and time( "2012-12-22T03:45:00" ) = duration( "P2DT20H14M" ) duration( "P2Y2M" ) = duration( "P26M" )
- years and months duration( from, to )
-
Calculates the
years and months duration
between the two specified parameters.Table 16. Parameters Parameter Type from
date
ordate and time
to
date
ordate and time
Exampleyears and months duration( date( "2011-12-22" ), date( "2013-08-24" ) ) = duration( "P1Y8M" )
Boolean functions
The following functions support Boolean operations.
- not( negand )
-
Performs the logical negation of the
negand
operand.Table 17. Parameters Parameter Type negand
boolean
Examplesnot( true ) = false not( null ) = null
String functions
The following functions support string operations.
| In FEEL, Unicode characters are counted based on their code points. |
- substring( string, start position, length? )
-
Returns the substring from the start position for the specified length. The first character is at position value
1
.Table 18. Parameters Parameter Type string
string
start position
number
length
(Optional)number
Examplessubstring( "testing",3 ) = "sting" substring( "testing",3,3 ) = "sti" substring( "testing", -2, 1 ) = "n" substring( "\U01F40Eab", 2 ) = "ab"
In FEEL, the string literal "\U01F40Eab"
is the🐎ab
string (horse symbol followed bya
andb
).
- string length( string )
-
Calculates the length of the specified string.
Table 19. Parameters Parameter Type string
string
Examplesstring length( "tes" ) = 3 string length( "\U01F40Eab" ) = 3
- upper case( string )
-
Produces an uppercase version of the specified string.
Table 20. Parameters Parameter Type string
string
Exampleupper case( "aBc4" ) = "ABC4"
- lower case( string )
-
Produces a lowercase version of the specified string.
Table 21. Parameters Parameter Type string
string
Examplelower case( "aBc4" ) = "abc4"
- substring before( string, match )
-
Calculates the substring before the match.
Table 22. Parameters Parameter Type string
string
match
string
Examplessubstring before( "testing", "ing" ) = "test" substring before( "testing", "xyz" ) = ""
- substring after( string, match )
-
Calculates the substring after the match.
Table 23. Parameters Parameter Type string
string
match
string
Examplessubstring after( "testing", "test" ) = "ing" substring after( "", "a" ) = ""
- replace( input, pattern, replacement, flags? )
-
Calculates the regular expression replacement.
Table 24. Parameters Parameter Type input
string
pattern
string
replacement
string
flags
(Optional)string
This function uses regular expression parameters as defined in XQuery 1.0 and XPath 2.0 Functions and Operators. Examplereplace( "abcd", "(ab)|(a)", "[1=$1][2=$2]" ) = "[1=ab][2=]cd"
- contains( string, match )
-
Returns
true
if the string contains the match.Table 25. Parameters Parameter Type string
string
match
string
Examplecontains( "testing", "to" ) = false
- starts with( string, match )
-
Returns
true
if the string starts with the matchTable 26. Parameters Parameter Type string
string
match
string
Examplestarts with( "testing", "te" ) = true
- ends with( string, match )
-
Returns
true
if the string ends with the match.Table 27. Parameters Parameter Type string
string
match
string
Exampleends with( "testing", "g" ) = true
- matches( input, pattern, flags? )
-
Returns
true
if the input matches the regular expression.Table 28. Parameters Parameter Type input
string
pattern
string
flags
(Optional)string
This function uses regular expression parameters as defined in XQuery 1.0 and XPath 2.0 Functions and Operators. Examplematches( "teeesting", "^te*sting" ) = true
- split( string, delimiter )
-
Returns a list of the original string and splits it at the delimiter regular expression pattern.
Table 29. Parameters Parameter Type string
string
delimiter
string
for a regular expression patternThis function uses regular expression parameters as defined in XQuery 1.0 and XPath 2.0 Functions and Operators. Examplessplit( "John Doe", "\\s" ) = ["John", "Doe"] split( "a;b;c;;", ";" ) = ["a","b","c","",""]
List functions
The following functions support list operations.
In FEEL, the index of the first element in a list is 1 . The index of the last element in a list can be identified as -1 .
|
- list contains( list, element )
-
Returns
true
if the list contains the element.Table 30. Parameters Parameter Type list
list
element
Any type, including null
Examplelist contains( [1,2,3], 2 ) = true
- count( list )
-
Counts the elements in the list.
Table 31. Parameters Parameter Type list
list
Examplescount( [1,2,3] ) = 3 count( [] ) = 0 count( [1,[2,3]] ) = 2
- min( list )
-
Returns the minimum comparable element in the list.
Table 32. Parameters Parameter Type list
list
Alternative signaturemin( e1, e2, ..., eN )
Examplesmin( [1,2,3] ) = 1 min( 1 ) = 1 min( [1] ) = 1
- max( list )
-
Returns the maximum comparable element in the list.
Table 33. Parameters Parameter Type list
list
Alternative signaturemax( e1, e2, ..., eN )
Examplesmax( 1,2,3 ) = 3 max( [] ) = null
- sum( list )
-
Returns the sum of the numbers in the list.
Table 34. Parameters Parameter Type list
list
ofnumber
elementsAlternative signaturesum( n1, n2, ..., nN )
Examplessum( [1,2,3] ) = 6 sum( 1,2,3 ) = 6 sum( 1 ) = 1 sum( [] ) = null
- mean( list )
-
Calculates the average (arithmetic mean) of the elements in the list.
Table 35. Parameters Parameter Type list
list
ofnumber
elementsAlternative signaturemean( n1, n2, ..., nN )
Examplesmean( [1,2,3] ) = 2 mean( 1,2,3 ) = 2 mean( 1 ) = 1 mean( [] ) = null
- all( list )
-
Returns
true
if all elements in the list are true.Table 36. Parameters Parameter Type list
list
ofboolean
elementsAlternative signatureall( b1, b2, ..., bN )
Examplesall( [false,null,true] ) = false all( true ) = true all( [true] ) = true all( [] ) = true all( 0 ) = null
- any( list )
-
Returns
true
if any element in the list is true.Table 37. Parameters Parameter Type list
list
ofboolean
elementsAlternative signatureany( b1, b2, ..., bN )
Examplesany( [false,null,true] ) = true any( false ) = false any( [] ) = false any( 0 ) = null
- sublist( list, start position, length? )
-
Returns the sublist from the start position, limited to the length elements.
Table 38. Parameters Parameter Type list
list
start position
number
length
(Optional)number
Examplesublist( [4,5,6], 1, 2 ) = [4,5]
- append( list, item )
-
Creates a list that is appended to the item or items.
Table 39. Parameters Parameter Type list
list
item
Any type
Exampleappend( [1], 2, 3 ) = [1,2,3]
- concatenate( list )
-
Creates a list that is the result of the concatenated lists.
Table 40. Parameters Parameter Type list
list
Exampleconcatenate( [1,2],[3] ) = [1,2,3]
- insert before( list, position, newItem )
-
Creates a list with the
newItem
inserted at the specified position.Table 41. Parameters Parameter Type list
list
position
number
newItem
Any type
Exampleinsert before( [1,3],1,2 ) = [2,1,3]
- remove( list, position )
-
Creates a list with the removed element excluded from the specified position.
Table 42. Parameters Parameter Type list
list
position
number
Exampleremove( [1,2,3], 2 ) = [1,3]
- reverse( list )
-
Returns a reversed list.
Table 43. Parameters Parameter Type list
list
Examplereverse( [1,2,3] ) = [3,2,1]
- index of( list, match )
-
Returns indexes matching the element.
Parameters-
list
of typelist
-
match
of any type
Table 44. Parameters Parameter Type list
list
match
Any type
Exampleindex of( [1,2,3,2],2 ) = [2,4]
-
- union( list )
-
Returns a list of all the elements from multiple lists and excludes duplicates.
Table 45. Parameters Parameter Type list
list
Exampleunion( [1,2],[2,3] ) = [1,2,3]
- distinct values( list )
-
Returns a list of elements from a single list and excludes duplicates.
Table 46. Parameters Parameter Type list
list
Exampledistinct values( [1,2,3,2,1] ) = [1,2,3]
- flatten( list )
-
Returns a flattened list.
Table 47. Parameters Parameter Type list
list
Exampleflatten( [[1,2],[[3]], 4] ) = [1,2,3,4]
- product( list )
-
Returns the product of the numbers in the list.
Table 48. Parameters Parameter Type list
list
ofnumber
elementsAlternative signatureproduct( n1, n2, ..., nN )
Examplesproduct( [2, 3, 4] ) = 24 product( 2, 3, 4 ) = 24
- median( list )
-
Returns the median of the numbers in the list. If the number of elements is odd, the result is the middle element. If the number of elements is even, the result is the average of the two middle elements.
Table 49. Parameters Parameter Type list
list
ofnumber
elementsAlternative signaturemedian( n1, n2, ..., nN )
Examplesmedian( 8, 2, 5, 3, 4 ) = 4 median( [6, 1, 2, 3] ) = 2.5 median( [ ] ) = null
- stddev( list )
-
Returns the standard deviation of the numbers in the list.
Table 50. Parameters Parameter Type list
list
ofnumber
elementsAlternative signaturestddev( n1, n2, ..., nN )
Examplesstddev( 2, 4, 7, 5 ) = 2.081665999466132735282297706979931 stddev( [47] ) = null stddev( 47 ) = null stddev( [ ] ) = null
- mode( list )
-
Returns the mode of the numbers in the list. If multiple elements are returned, the numbers are sorted in ascending order.
Table 51. Parameters Parameter Type list
list
ofnumber
elementsAlternative signaturemode( n1, n2, ..., nN )
Examplesmode( 6, 3, 9, 6, 6 ) = [6] mode( [6, 1, 9, 6, 1] ) = [1, 6] mode( [ ] ) = [ ]
Numeric functions
The following functions support number operations.
- decimal( n, scale )
-
Returns a number with the specified scale.
Table 52. Parameters Parameter Type n
number
scale
number
in the range[−6111..6176]
Examplesdecimal( 1/3, 2 ) = .33 decimal( 1.5, 0 ) = 2 decimal( 2.5, 0 ) = 2
- floor( n )
-
Returns the greatest integer that is less than or equal to the specified number.
Table 53. Parameters Parameter Type n
number
Examplesfloor( 1.5 ) = 1 floor( -1.5 ) = -2
- ceiling( n )
-
Returns the smallest integer that is greater than or equal to the specified number.
Table 54. Parameters Parameter Type n
number
Examplesceiling( 1.5 ) = 2 ceiling( -1.5 ) = -1
- abs( n )
-
Returns the absolute value.
Table 55. Parameters Parameter Type n
number
,days and time duration
, oryears and months duration
Examplesabs( 10 ) = 10 abs( -10 ) = 10 abs( @"PT5H" ) = @"PT5H" abs( @"-PT5H" ) = @"PT5H"
- modulo( dividend, divisor )
-
Returns the remainder of the division of the dividend by the divisor. If either the dividend or divisor is negative, the result is of the same sign as the divisor.
This function is also expressed as modulo(dividend, divisor) = dividend - divisor*floor(dividen d/divisor)
.Table 56. Parameters Parameter Type dividend
number
divisor
number
Examplesmodulo( 12, 5 ) = 2 modulo( -12,5 )= 3 modulo( 12,-5 )= -3 modulo( -12,-5 )= -2 modulo( 10.1, 4.5 )= 1.1 modulo( -10.1, 4.5 )= 3.4 modulo( 10.1, -4.5 )= -3.4 modulo( -10.1, -4.5 )= -1.1
- sqrt( number )
-
Returns the square root of the specified number.
Table 57. Parameters Parameter Type n
number
Examplesqrt( 16 ) = 4
- log( number )
-
Returns the logarithm of the specified number.
Table 58. Parameters Parameter Type n
number
Exampledecimal( log( 10 ), 2 ) = 2.30
- exp( number )
-
Returns Euler’s number
e
raised to the power of the specified number.Table 59. Parameters Parameter Type n
number
Exampledecimal( exp( 5 ), 2 ) = 148.41
- odd( number )
-
Returns
true
if the specified number is odd.Table 60. Parameters Parameter Type n
number
Examplesodd( 5 ) = true odd( 2 ) = false
- even( number )
-
Returns
true
if the specified number is even.Table 61. Parameters Parameter Type n
number
Exampleseven( 5 ) = false even ( 2 ) = true
Date and time functions
The following functions support date and time operations.
- is( value1, value2 )
-
Returns
true
if both values are the same element in the FEEL semantic domain.Table 62. Parameters Parameter Type value1
Any type
value2
Any type
Examplesis( date( "2012-12-25" ), time( "23:00:50" ) ) = false is( date( "2012-12-25" ), date( "2012-12-25" ) ) = true is( time( "23:00:50z" ), time( "23:00:50" ) ) = false
Range functions
The following functions support temporal ordering operations to establish relationships between single scalar values and ranges of such values. These functions are similar to the components in the Health Level Seven (HL7) International Clinical Quality Language (CQL) 1.4 syntax.
- before( )
-
Returns
true
when an elementA
is before an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
before( point1 point2 )
-
before( point range )
-
before( range point )
-
before( range1,range2 )
Requirements for evaluating totrue
-
point1 < point2
-
point < range.start or ( point = range.start and not(range.start included) )
-
range.end < point or ( range.end = point and not(range.end included) )
-
range1.end < range2.start or (( not(range1.end included) or not(range2.start included) ) and range1.end = range2.start )
Examplesbefore( 1, 10 ) = true before( 10, 1 ) = false before( 1, [1..10] ) = false before( 1, (1..10] ) = true before( 1, [5..10] ) = true before( [1..10], 10 ) = false before( [1..10), 10 ) = true before( [1..10], 15 ) = true before( [1..10], [15..20] ) = true before( [1..10], [10..20] ) = false before( [1..10), [10..20] ) = true before( [1..10], (10..20] ) = true
-
- after( )
-
Returns
true
when an elementA
is after an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
after( point1 point2 )
-
after( point range )
-
after( range, point )
-
after( range1 range2 )
Requirements for evaluating totrue
-
point1 > point2
-
point > range.end or ( point = range.end and not(range.end included) )
-
range.start > point or ( range.start = point and not(range.start included) )
-
range1.start > range2.end or (( not(range1.start included) or not(range2.end included) ) and range1.start = range2.end )
Examplesafter( 10, 5 ) = true after( 5, 10 ) = false after( 12, [1..10] ) = true after( 10, [1..10) ) = true after( 10, [1..10] ) = false after( [11..20], 12 ) = false after( [11..20], 10 ) = true after( (11..20], 11 ) = true after( [11..20], 11 ) = false after( [11..20], [1..10] ) = true after( [1..10], [11..20] ) = false after( [11..20], [1..11) ) = true after( (11..20], [1..11] ) = true
-
- meets( )
-
Returns
true
when an elementA
meets an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
meets( range1, range2 )
Requirements for evaluating totrue
-
range1.end included and range2.start included and range1.end = range2.start
Examplesmeets( [1..5], [5..10] ) = true meets( [1..5), [5..10] ) = false meets( [1..5], (5..10] ) = false meets( [1..5], [6..10] ) = false
-
- met by( )
-
Returns
true
when an elementA
is met by an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
met by( range1, range2 )
Requirements for evaluating totrue
-
range1.start included and range2.end included and range1.start = range2.end
Examplesmet by( [5..10], [1..5] ) = true met by( [5..10], [1..5) ) = false met by( (5..10], [1..5] ) = false met by( [6..10], [1..5] ) = false
-
- overlaps( )
-
Returns
true
when an elementA
overlaps an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
overlaps( range1, range2 )
Requirements for evaluating totrue
-
( range1.end > range2.start or (range1.end = range2.start and (range1.end included or range2.end included)) ) and ( range1.start < range2.end or (range1.start = range2.end and range1.start included and range2.end included) )
Examplesoverlaps( [1..5], [3..8] ) = true overlaps( [3..8], [1..5] ) = true overlaps( [1..8], [3..5] ) = true overlaps( [3..5], [1..8] ) = true overlaps( [1..5], [6..8] ) = false overlaps( [6..8], [1..5] ) = false overlaps( [1..5], [5..8] ) = true overlaps( [1..5], (5..8] ) = false overlaps( [1..5), [5..8] ) = false overlaps( [1..5), (5..8] ) = false overlaps( [5..8], [1..5] ) = true overlaps( (5..8], [1..5] ) = false overlaps( [5..8], [1..5) ) = false overlaps( (5..8], [1..5) ) = false
-
- overlaps before( )
-
Returns
true
when an elementA
overlaps before an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
overlaps before( range1 range2 )
Requirements for evaluating totrue
-
( range1.start < range2.start or (range1.start = range2.start and range1.start included and range2.start included) ) and ( range1.end > range2.start or (range1.end = range2.start and range1.end included and range2.start included) ) and ( range1.end < range2.end or (range1.end = range2.end and (not(range1.end included) or range2.end included )) )
Examplesoverlaps before( [1..5], [3..8] ) = true overlaps before( [1..5], [6..8] ) = false overlaps before( [1..5], [5..8] ) = true overlaps before( [1..5], (5..8] ) = false overlaps before( [1..5), [5..8] ) = false overlaps before( [1..5), (1..5] ) = true overlaps before( [1..5], (1..5] ) = true overlaps before( [1..5), [1..5] ) = false overlaps before( [1..5], [1..5] ) = false
-
- overlaps after( )
-
Returns
true
when an elementA
overlaps after an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
overlaps after( range1 range2 )
Requirements for evaluating totrue
-
( range2.start < range1.start or (range2.start = range1.start and range2.start included and not( range1.start included)) ) and ( range2.end > range1.start or (range2.end = range1.start and range2.end included and range1.start included) ) and ( range2.end < range1.end or (range2.end = range1.end and (not(range2.end included) or range1.end included)) )
Examplesoverlaps after( [3..8], [1..5] )= true overlaps after( [6..8], [1..5] )= false overlaps after( [5..8], [1..5] )= true overlaps after( (5..8], [1..5] )= false overlaps after( [5..8], [1..5) )= false overlaps after( (1..5], [1..5) )= true overlaps after( (1..5], [1..5] )= true overlaps after( [1..5], [1..5) )= false overlaps after( [1..5], [1..5] )= false overlaps after( (1..5), [1..5] )= false overlaps after( (1..5], [1..6] )= false overlaps after( (1..5], (1..5] )= false overlaps after( (1..5], [2..5] )= false
-
- finishes( )
-
Returns
true
when an elementA
finishes an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
finishes( point, range )
-
finishes( range1, range2 )
Requirements for evaluating totrue
-
range.end included and range.end = point
-
range1.end included = range2.end included and range1.end = range2.end and ( range1.start > range2.start or (range1.start = range2.start and (not(range1.start included) or range2.start included)) )
Examplesfinishes( 10, [1..10] ) = true finishes( 10, [1..10) ) = false finishes( [5..10], [1..10] ) = true finishes( [5..10), [1..10] ) = false finishes( [5..10), [1..10) ) = true finishes( [1..10], [1..10] ) = true finishes( (1..10], [1..10] ) = true
-
- finished by( )
-
Returns
true
when an elementA
is finished by an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
finished by( range, point )
-
finished by( range1 range2 )
Requirements for evaluating totrue
-
range.end included and range.end = point
-
range1.end included = range2.end included and range1.end = range2.end and ( range1.start < range2.start or (range1.start = range2.start and (range1.start included or not(range2.start included))) )
Examplesfinished by( [1..10], 10 ) = true finished by( [1..10), 10 ) = false finished by( [1..10], [5..10] ) = true finished by( [1..10], [5..10) ) = false finished by( [1..10), [5..10) ) = true finished by( [1..10], [1..10] ) = true finished by( [1..10], (1..10] ) = true
-
- includes( )
-
Returns
true
when an elementA
includes an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
includes( range, point )
-
includes( range1, range2 )
Requirements for evaluating totrue
-
(range.start < point and range.end > point) or (range.start = point and range.start included) or (range.end = point and range.end included)
-
( range1.start < range2.start or (range1.start = range2.start and (range1.start included or not(range2.start included))) ) and ( range1.end > range2.end or (range1.end = range2.end and (range1.end included or not(range2.end included))) )
Examplesincludes( [1..10], 5 ) = true includes( [1..10], 12 ) = false includes( [1..10], 1 ) = true includes( [1..10], 10 ) = true includes( (1..10], 1 ) = false includes( [1..10), 10 ) = false includes( [1..10], [4..6] ) = true includes( [1..10], [1..5] ) = true includes( (1..10], (1..5] ) = true includes( [1..10], (1..10) ) = true includes( [1..10), [5..10) ) = true includes( [1..10], [1..10) ) = true includes( [1..10], (1..10] ) = true includes( [1..10], [1..10] ) = true
-
- during( )
-
Returns
true
when an elementA
is during an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
during( point, range )
-
during( range1 range2 )
Requirements for evaluating totrue
-
(range.start < point and range.end > point) or (range.start = point and range.start included) or (range.end = point and range.end included)
-
( range2.start < range1.start or (range2.start = range1.start and (range2.start included or not(range1.start included))) ) and ( range2.end > range1.end or (range2.end = range1.end and (range2.end included or not(range1.end included))) )
Examplesduring( 5, [1..10] ) = true during( 12, [1..10] ) = false during( 1, [1..10] ) = true during( 10, [1..10] ) = true during( 1, (1..10] ) = false during( 10, [1..10) ) = false during( [4..6], [1..10] ) = true during( [1..5], [1..10] ) = true during( (1..5], (1..10] ) = true during( (1..10), [1..10] ) = true during( [5..10), [1..10) ) = true during( [1..10), [1..10] ) = true during( (1..10], [1..10] ) = true during( [1..10], [1..10] ) = true
-
- starts( )
-
Returns
true
when an elementA
starts an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
starts( point, range )
-
starts( range1, range2 )
Requirements for evaluating totrue
-
range.start = point and range.start included
-
range1.start = range2.start and range1.start included = range2.start included and ( range1.end < range2.end or (range1.end = range2.end and (not(range1.end included) or range2.end included)) )
Examplesstarts( 1, [1..10] ) = true starts( 1, (1..10] ) = false starts( 2, [1..10] ) = false starts( [1..5], [1..10] ) = true starts( (1..5], (1..10] ) = true starts( (1..5], [1..10] ) = false starts( [1..5], (1..10] ) = false starts( [1..10], [1..10] ) = true starts( [1..10), [1..10] ) = true starts( (1..10), (1..10) ) = true
-
- started by( )
-
Returns
true
when an elementA
is started by an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
started by( range, point )
-
started by( range1, range2 )
Requirements for evaluating totrue
-
range.start = point and range.start included
-
range1.start = range2.start and range1.start included = range2.start included and ( range2.end < range1.end or (range2.end = range1.end and (not(range2.end included) or range1.end included)) )
Examplesstarted by( [1..10], 1 ) = true started by( (1..10], 1 ) = false started by( [1..10], 2 ) = false started by( [1..10], [1..5] ) = true started by( (1..10], (1..5] ) = true started by( [1..10], (1..5] ) = false started by( (1..10], [1..5] ) = false started by( [1..10], [1..10] ) = true started by( [1..10], [1..10) ) = true started by( (1..10), (1..10) ) = true
-
- coincides( )
-
Returns
true
when an elementA
coincides with an elementB
and when the relevant requirements for evaluating totrue
are also met.Signatures-
coincides( point1, point2 )
-
coincides( range1, range2 )
Requirements for evaluating totrue
-
point1 = point2
-
range1.start = range2.start and range1.start included = range2.start included and range1.end = range2.end and range1.end included = range2.end included
Examplescoincides( 5, 5 ) = true coincides( 3, 4 ) = false coincides( [1..5], [1..5] ) = true coincides( (1..5), [1..5] ) = false coincides( [1..5], [2..6] ) = false
-
Temporal functions
The following functions support general temporal operations.
- day of year( date )
-
Returns the Gregorian number of the day of the year.
Table 63. Parameters Parameter Type date
date
ordate and time
Exampleday of year( date(2019, 9, 17) ) = 260
- day of week( date )
-
Returns the Gregorian day of the week:
"Monday"
,"Tuesday"
,"Wednesday"
,"Thursday"
,"Friday"
,"Saturday"
, or"Sunday"
.Table 64. Parameters Parameter Type date
date
ordate and time
Exampleday of week( date(2019, 9, 17) ) = "Tuesday"
- month of year( date )
-
Returns the Gregorian month of the year:
"January"
,"February"
,"March"
,"April"
,"May"
,"June"
,"July"
,"August"
,"September"
,"October"
,"November"
, or"December"
.Table 65. Parameters Parameter Type date
date
ordate and time
Examplemonth of year( date(2019, 9, 17) ) = "September"
- month of year( date )
-
Returns the Gregorian week of the year as defined by ISO 8601.
Table 66. Parameters Parameter Type date
date
ordate and time
Examplesweek of year( date(2019, 9, 17) ) = 38 week of year( date(2003, 12, 29) ) = 1 week of year( date(2004, 1, 4) ) = 1 week of year( date(2005, 1, 1) ) = 53 week of year( date(2005, 1, 3) ) = 1 week of year( date(2005, 1, 9) ) = 1
Sort functions
The following functions support sorting operations.
- sort( list, precedes )
-
Returns a list of the same elements but ordered according to the sorting function.
Table 67. Parameters Parameter Type list
list
precedes
function
Examplesort( list: [3,1,4,5,2], precedes: function(x,y) x < y ) = [1,2,3,4,5]
Context functions
The following functions support context operations.
- get value( m, key )
-
Returns the value from the context for the specified entry key.
Table 68. Parameters Parameter Type m
context
key
string
Examplesget value( {key1 : "value1"}, "key1" ) = "value1" get value( {key1 : "value1"}, "unexistent-key" ) = null
- get entries( m )
-
Returns a list of key-value pairs for the specified context.
Table 69. Parameters Parameter Type m
context
Exampleget entries( {key1 : "value1", key2 : "value2"} ) = [ { key : "key1", value : "value1" }, {key : "key2", value : "value2"} ]
<IP_ADDRESS>. Variable and function names in FEEL
Unlike many traditional expression languages, Friendly Enough Expression Language (FEEL) supports spaces and a few special characters as part of variable and function names. A FEEL name must start with a letter
, ?
, or _
element. The unicode letter characters are also allowed. Variable names cannot start with a language keyword, such as and
, true
, or every
. The remaining characters in a variable name can be any of the starting characters, as well as digits
, white spaces, and special characters such as +
, -
, /
, *
, '
, and .
.
For example, the following names are all valid FEEL names:
-
Age
-
Birth Date
-
Flight 234 pre-check procedure
Several limitations apply to variable and function names in FEEL:
- Ambiguity
-
The use of spaces, keywords, and other special characters as part of names can make FEEL ambiguous. The ambiguities are resolved in the context of the expression, matching names from left to right. The parser resolves the variable name as the longest name matched in scope. You can use
( )
to disambiguate names if necessary. - Spaces in names
-
The DMN specification limits the use of spaces in FEEL names. According to the DMN specification, names can contain multiple spaces but not two consecutive spaces.
In order to make the language easier to use and avoid common errors due to spaces, Kogito removes the limitation on the use of consecutive spaces. Kogito supports variable names with any number of consecutive spaces, but normalizes them into a single space. For example, the variable references
First Name
with one space andFirst Name
with two spaces are both acceptable in Kogito.Kogito also normalizes the use of other white spaces, like the non-breakable white space that is common in web pages, tabs, and line breaks. From a Kogito FEEL engine perspective, all of these characters are normalized into a single white space before processing.
- The keyword
in
-
The keyword
in
is the only keyword in the language that cannot be used as part of a variable name. Although the specifications allow the use of keywords in the middle of variable names, the use ofin
in variable names conflicts with the grammar definition offor
,every
andsome
expression constructs.
<IP_ADDRESS>. DMN decision tables
A decision table in DMN is a visual representation of one or more business rules in a tabular format. You use decision tables to define rules for a decision node that applies those rules at a given point in the decision model. Each rule consists of a single row in the table, and includes columns that define the conditions (input) and outcome (output) for that particular row. The definition of each row is precise enough to derive the outcome using the values of the conditions. Input and output values can be FEEL expressions or defined data type values.
For example, the following decision table determines credit score ratings based on a defined range of a loan applicant’s credit score:
The following decision table determines the next step in a lending strategy for applicants depending on applicant loan eligibility and the bureau call type:
The following decision table determines applicant qualification for a loan as the concluding decision node in a loan prequalification decision model:
Decision tables are a popular way of modeling rules and decision logic, and are used in many methodologies (such as DMN) and implementation frameworks (such as Drools).
| Kogito supports both DMN decision tables and Drools-native decision tables, but they are different types of assets with different syntax requirements and are not interchangeable. For more information about Drools-native decision tables in Kogito, see Spreadsheet decision tables. |
Hit policies in DMN decision tables
Hit policies determine how to reach an outcome when multiple rules in a decision table match the provided input values. For example, if one rule in a decision table applies a sales discount to military personnel and another rule applies a discount to students, then when a customer is both a student and in the military, the decision table hit policy must indicate whether to apply one discount or the other (Unique, First) or both discounts (Collect Sum). You specify the single character of the hit policy (U, F, C+) in the upper-left corner of the decision table.
The following decision table hit policies are supported in DMN:
-
Unique (U): Permits only one rule to match. Any overlap raises an error.
-
Any (A): Permits multiple rules to match, but they must all have the same output. If multiple matching rules do not have the same output, an error is raised.
-
Priority (P): Permits multiple rules to match, with different outputs. The output that comes first in the output values list is selected.
-
First (F): Uses the first match in rule order.
-
Collect (C+, C>, C<, C#): Aggregates output from multiple rules based on an aggregation function.
-
Collect ( C ): Aggregates values in an arbitrary list.
-
Collect Sum (C+): Outputs the sum of all collected values. Values must be numeric.
-
Collect Min (C<): Outputs the minimum value among the matches. The resulting values must be comparable, such as numbers, dates, or text (lexicographic order).
-
Collect Max (C>): Outputs the maximum value among the matches. The resulting values must be comparable, such as numbers, dates or text (lexicographic order).
-
Collect Count (C#): Outputs the number of matching rules.
-
<IP_ADDRESS>. Boxed literal expressions
A boxed literal expression in DMN is a literal FEEL expression as text in a table cell, typically with a labeled column and an assigned data type. You use boxed literal expressions to define simple or complex node logic or decision data directly in FEEL for a particular node in a decision. Literal FEEL expressions must conform to FEEL syntax requirements in the OMG Decision Model and Notation specification.
For example, the following boxed literal expression defines the minimum acceptable PITI calculation (principal, interest, taxes, and insurance) in a lending decision, where acceptable rate
is a variable defined in the DMN model:
The following boxed literal expression sorts a list of possible dating candidates (soul mates) in an online dating application based on their score on criteria such as age, location, and interests:
<IP_ADDRESS>. Boxed context expressions
A boxed context expression in DMN is a set of variable names and values with a result value. Each name-value pair is a context entry. You use context expressions to represent data definitions in decision logic and set a value for a desired decision element within the DMN decision model. A value in a boxed context expression can be a data type value or FEEL expression, or can contain a nested sub-expression of any type, such as a decision table, a literal expression, or another context expression.
For example, the following boxed context expression defines the factors for sorting delayed passengers in a flight-rebooking decision model, based on defined data types (tPassengerTable
, tFlightNumberList
):
The following boxed context expression defines the factors that determine whether a loan applicant can meet minimum mortgage payments based on principal, interest, taxes, and insurance (PITI), represented as a front-end ratio calculation with a sub-context expression:
<IP_ADDRESS>. Boxed relation expressions
A boxed relation expression in DMN is a traditional data table with information about given entities, listed as rows. You use boxed relation tables to define decision data for relevant entities in a decision at a particular node. Boxed relation expressions are similar to context expressions in that they set variable names and values, but relation expressions contain no result value and list all variable values based on a single defined variable in each column.
For example, the following boxed relation expression provides information about employees in an employee rostering decision:
<IP_ADDRESS>. Boxed function expressions
A boxed function expression in DMN is a parameterized boxed expression containing a literal FEEL expression, a nested context expression of an external JAVA or PMML function, or a nested boxed expression of any type. By default, all business knowledge models are defined as boxed function expressions. You use boxed function expressions to call functions on your decision logic and to define all business knowledge models.
For example, the following boxed function expression determines airline flight capacity in a flight-rebooking decision model:
The following boxed function expression contains a basic Java function as a context expression for determining absolute value in a decision model calculation:
The following boxed function expression determines a monthly mortgage installment as a business knowledge model in a lending decision, with the function value defined as a nested context expression:
The following boxed function expression uses a PMML model included in the DMN file to define the minimum acceptable PITI calculation (principal, interest, taxes, and insurance) in a lending decision:
<IP_ADDRESS>. Boxed invocation expressions
A boxed invocation expression in DMN is a boxed expression that invokes a business knowledge model. A boxed invocation expression contains the name of the business knowledge model to be invoked and a list of parameter bindings. Each binding is represented by two boxed expressions on a row: The box on the left contains the name of a parameter and the box on the right contains the binding expression whose value is assigned to the parameter to evaluate the invoked business knowledge model. You use boxed invocations to invoke at a particular decision node a business knowledge model defined in the decision model.
For example, the following boxed invocation expression invokes a Reassign Next Passenger
business knowledge model as the concluding decision node in a flight-rebooking decision model:
The following boxed invocation expression invokes an InstallmentCalculation
business knowledge model to calculate a monthly installment amount for a loan before proceeding to affordability decisions:
<IP_ADDRESS>. Boxed list expressions
A boxed list expression in DMN represents a FEEL list of items. You use boxed lists to define lists of relevant items for a particular node in a decision. You can also use literal FEEL expressions for list items in cells to create more complex lists.
For example, the following boxed list expression identifies approved credit score agencies in a loan application decision service:
The following boxed list expression also identifies approved credit score agencies but uses FEEL logic to define the agency status (Inc., LLC, SA, GA) based on a DMN input node:
5.1.4. DMN model example
The following is a real-world DMN model example that demonstrates how you can use decision modeling to reach a decision based on input data, circumstances, and company guidelines. In this scenario, a flight from San Diego to New York is canceled, requiring the affected airline to find alternate arrangements for its inconvenienced passengers.
First, the airline collects the information necessary to determine how best to get the travelers to their destinations:
- Input data
-
-
List of flights
-
List of passengers
-
- Decisions
-
-
Prioritize the passengers who will get seats on a new flight
-
Determine which flights those passengers will be offered
-
- Business knowledge models
-
-
The company process for determining passenger priority
-
Any flights that have space available
-
Company rules for determining how best to reassign inconvenienced passengers
-
The airline then uses the DMN standard to model its decision process in the following decision requirements diagram (DRD) for determining the best rebooking solution:
Similar to flowcharts, DRDs use shapes to represent the different elements in a process. Ovals contain the two necessary input data, rectangles contain the decision points in the model, and rectangles with clipped corners (business knowledge models) contain reusable logic that can be repeatedly invoked.
The DRD draws logic for each element from boxed expressions that provide variable definitions using FEEL expressions or data type values.
Some boxed expressions are basic, such as the following decision for establishing a prioritized waiting list:
Some boxed expressions are more complex with greater detail and calculation, such as the following business knowledge model for reassigning the next delayed passenger:
The following is the DMN source file for this decision model:
<dmn:definitions xmlns="https://www.drools.org/kie-dmn/Flight-rebooking" xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd" xmlns:feel="http://www.omg.org/spec/FEEL/20140401" id="_0019_flight_rebooking" name="0019-flight-rebooking" namespace="https://www.drools.org/kie-dmn/Flight-rebooking">
<dmn:itemDefinition id="_tFlight" name="tFlight">
<dmn:itemComponent id="_tFlight_Flight" name="Flight Number">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_From" name="From">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_To" name="To">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_Dep" name="Departure">
<dmn:typeRef>feel:dateTime</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_Arr" name="Arrival">
<dmn:typeRef>feel:dateTime</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_Capacity" name="Capacity">
<dmn:typeRef>feel:number</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tFlight_Status" name="Status">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
</dmn:itemDefinition>
<dmn:itemDefinition id="_tFlightTable" isCollection="true" name="tFlightTable">
<dmn:typeRef>tFlight</dmn:typeRef>
</dmn:itemDefinition>
<dmn:itemDefinition id="_tPassenger" name="tPassenger">
<dmn:itemComponent id="_tPassenger_Name" name="Name">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tPassenger_Status" name="Status">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tPassenger_Miles" name="Miles">
<dmn:typeRef>feel:number</dmn:typeRef>
</dmn:itemComponent>
<dmn:itemComponent id="_tPassenger_Flight" name="Flight Number">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemComponent>
</dmn:itemDefinition>
<dmn:itemDefinition id="_tPassengerTable" isCollection="true" name="tPassengerTable">
<dmn:typeRef>tPassenger</dmn:typeRef>
</dmn:itemDefinition>
<dmn:itemDefinition id="_tFlightNumberList" isCollection="true" name="tFlightNumberList">
<dmn:typeRef>feel:string</dmn:typeRef>
</dmn:itemDefinition>
<dmn:inputData id="i_Flight_List" name="Flight List">
<dmn:variable name="Flight List" typeRef="tFlightTable"/>
</dmn:inputData>
<dmn:inputData id="i_Passenger_List" name="Passenger List">
<dmn:variable name="Passenger List" typeRef="tPassengerTable"/>
</dmn:inputData>
<dmn:decision name="Prioritized Waiting List" id="d_PrioritizedWaitingList">
<dmn:variable name="Prioritized Waiting List" typeRef="tPassengerTable"/>
<dmn:informationRequirement>
<dmn:requiredInput href="#i_Passenger_List"/>
</dmn:informationRequirement>
<dmn:informationRequirement>
<dmn:requiredInput href="#i_Flight_List"/>
</dmn:informationRequirement>
<dmn:knowledgeRequirement>
<dmn:requiredKnowledge href="#b_PassengerPriority"/>
</dmn:knowledgeRequirement>
<dmn:context>
<dmn:contextEntry>
<dmn:variable name="Cancelled Flights" typeRef="tFlightNumberList"/>
<dmn:literalExpression>
<dmn:text>Flight List[ Status = "cancelled" ].Flight Number</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Waiting List" typeRef="tPassengerTable"/>
<dmn:literalExpression>
<dmn:text>Passenger List[ list contains( Cancelled Flights, Flight Number ) ]</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:literalExpression>
<dmn:text>sort( Waiting List, passenger priority )</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
</dmn:context>
</dmn:decision>
<dmn:decision name="Rebooked Passengers" id="d_RebookedPassengers">
<dmn:variable name="Rebooked Passengers" typeRef="tPassengerTable"/>
<dmn:informationRequirement>
<dmn:requiredDecision href="#d_PrioritizedWaitingList"/>
</dmn:informationRequirement>
<dmn:informationRequirement>
<dmn:requiredInput href="#i_Flight_List"/>
</dmn:informationRequirement>
<dmn:knowledgeRequirement>
<dmn:requiredKnowledge href="#b_ReassignNextPassenger"/>
</dmn:knowledgeRequirement>
<dmn:invocation>
<dmn:literalExpression>
<dmn:text>reassign next passenger</dmn:text>
</dmn:literalExpression>
<dmn:binding>
<dmn:parameter name="Waiting List"/>
<dmn:literalExpression>
<dmn:text>Prioritized Waiting List</dmn:text>
</dmn:literalExpression>
</dmn:binding>
<dmn:binding>
<dmn:parameter name="Reassigned Passengers List"/>
<dmn:literalExpression>
<dmn:text>[]</dmn:text>
</dmn:literalExpression>
</dmn:binding>
<dmn:binding>
<dmn:parameter name="Flights"/>
<dmn:literalExpression>
<dmn:text>Flight List</dmn:text>
</dmn:literalExpression>
</dmn:binding>
</dmn:invocation>
</dmn:decision>
<dmn:businessKnowledgeModel id="b_PassengerPriority" name="passenger priority">
<dmn:encapsulatedLogic>
<dmn:formalParameter name="Passenger1" typeRef="tPassenger"/>
<dmn:formalParameter name="Passenger2" typeRef="tPassenger"/>
<dmn:decisionTable hitPolicy="UNIQUE">
<dmn:input id="b_Passenger_Priority_dt_i_P1_Status" label="Passenger1.Status">
<dmn:inputExpression typeRef="feel:string">
<dmn:text>Passenger1.Status</dmn:text>
</dmn:inputExpression>
<dmn:inputValues>
<dmn:text>"gold", "silver", "bronze"</dmn:text>
</dmn:inputValues>
</dmn:input>
<dmn:input id="b_Passenger_Priority_dt_i_P2_Status" label="Passenger2.Status">
<dmn:inputExpression typeRef="feel:string">
<dmn:text>Passenger2.Status</dmn:text>
</dmn:inputExpression>
<dmn:inputValues>
<dmn:text>"gold", "silver", "bronze"</dmn:text>
</dmn:inputValues>
</dmn:input>
<dmn:input id="b_Passenger_Priority_dt_i_P1_Miles" label="Passenger1.Miles">
<dmn:inputExpression typeRef="feel:string">
<dmn:text>Passenger1.Miles</dmn:text>
</dmn:inputExpression>
</dmn:input>
<dmn:output id="b_Status_Priority_dt_o" label="Passenger1 has priority">
<dmn:outputValues>
<dmn:text>true, false</dmn:text>
</dmn:outputValues>
<dmn:defaultOutputEntry>
<dmn:text>false</dmn:text>
</dmn:defaultOutputEntry>
</dmn:output>
<dmn:rule id="b_Passenger_Priority_dt_r1">
<dmn:inputEntry id="b_Passenger_Priority_dt_r1_i1">
<dmn:text>"gold"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r1_i2">
<dmn:text>"gold"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r1_i3">
<dmn:text>>= Passenger2.Miles</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="b_Passenger_Priority_dt_r1_o1">
<dmn:text>true</dmn:text>
</dmn:outputEntry>
</dmn:rule>
<dmn:rule id="b_Passenger_Priority_dt_r2">
<dmn:inputEntry id="b_Passenger_Priority_dt_r2_i1">
<dmn:text>"gold"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r2_i2">
<dmn:text>"silver","bronze"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r2_i3">
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="b_Passenger_Priority_dt_r2_o1">
<dmn:text>true</dmn:text>
</dmn:outputEntry>
</dmn:rule>
<dmn:rule id="b_Passenger_Priority_dt_r3">
<dmn:inputEntry id="b_Passenger_Priority_dt_r3_i1">
<dmn:text>"silver"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r3_i2">
<dmn:text>"silver"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r3_i3">
<dmn:text>>= Passenger2.Miles</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="b_Passenger_Priority_dt_r3_o1">
<dmn:text>true</dmn:text>
</dmn:outputEntry>
</dmn:rule>
<dmn:rule id="b_Passenger_Priority_dt_r4">
<dmn:inputEntry id="b_Passenger_Priority_dt_r4_i1">
<dmn:text>"silver"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r4_i2">
<dmn:text>"bronze"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r4_i3">
<dmn:text>-</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="b_Passenger_Priority_dt_r4_o1">
<dmn:text>true</dmn:text>
</dmn:outputEntry>
</dmn:rule>
<dmn:rule id="b_Passenger_Priority_dt_r5">
<dmn:inputEntry id="b_Passenger_Priority_dt_r5_i1">
<dmn:text>"bronze"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r5_i2">
<dmn:text>"bronze"</dmn:text>
</dmn:inputEntry>
<dmn:inputEntry id="b_Passenger_Priority_dt_r5_i3">
<dmn:text>>= Passenger2.Miles</dmn:text>
</dmn:inputEntry>
<dmn:outputEntry id="b_Passenger_Priority_dt_r5_o1">
<dmn:text>true</dmn:text>
</dmn:outputEntry>
</dmn:rule>
</dmn:decisionTable>
</dmn:encapsulatedLogic>
<dmn:variable name="passenger priority" typeRef="feel:boolean"/>
</dmn:businessKnowledgeModel>
<dmn:businessKnowledgeModel id="b_ReassignNextPassenger" name="reassign next passenger">
<dmn:encapsulatedLogic>
<dmn:formalParameter name="Waiting List" typeRef="tPassengerTable"/>
<dmn:formalParameter name="Reassigned Passengers List" typeRef="tPassengerTable"/>
<dmn:formalParameter name="Flights" typeRef="tFlightTable"/>
<dmn:context>
<dmn:contextEntry>
<dmn:variable name="Next Passenger" typeRef="tPassenger"/>
<dmn:literalExpression>
<dmn:text>Waiting List[1]</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Original Flight" typeRef="tFlight"/>
<dmn:literalExpression>
<dmn:text>Flights[ Flight Number = Next Passenger.Flight Number ][1]</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Best Alternate Flight" typeRef="tFlight"/>
<dmn:literalExpression>
<dmn:text>Flights[ From = Original Flight.From and To = Original Flight.To and Departure > Original Flight.Departure and Status = "scheduled" and has capacity( item, Reassigned Passengers List ) ][1]</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Reassigned Passenger" typeRef="tPassenger"/>
<dmn:context>
<dmn:contextEntry>
<dmn:variable name="Name" typeRef="feel:string"/>
<dmn:literalExpression>
<dmn:text>Next Passenger.Name</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Status" typeRef="feel:string"/>
<dmn:literalExpression>
<dmn:text>Next Passenger.Status</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Miles" typeRef="feel:number"/>
<dmn:literalExpression>
<dmn:text>Next Passenger.Miles</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Flight Number" typeRef="feel:string"/>
<dmn:literalExpression>
<dmn:text>Best Alternate Flight.Flight Number</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
</dmn:context>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Remaining Waiting List" typeRef="tPassengerTable"/>
<dmn:literalExpression>
<dmn:text>remove( Waiting List, 1 )</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:variable name="Updated Reassigned Passengers List" typeRef="tPassengerTable"/>
<dmn:literalExpression>
<dmn:text>append( Reassigned Passengers List, Reassigned Passenger )</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
<dmn:contextEntry>
<dmn:literalExpression>
<dmn:text>if count( Remaining Waiting List ) > 0 then reassign next passenger( Remaining Waiting List, Updated Reassigned Passengers List, Flights ) else Updated Reassigned Passengers List</dmn:text>
</dmn:literalExpression>
</dmn:contextEntry>
</dmn:context>
</dmn:encapsulatedLogic>
<dmn:variable name="reassign next passenger" typeRef="tPassengerTable"/>
<dmn:knowledgeRequirement>
<dmn:requiredKnowledge href="#b_HasCapacity"/>
</dmn:knowledgeRequirement>
</dmn:businessKnowledgeModel>
<dmn:businessKnowledgeModel id="b_HasCapacity" name="has capacity">
<dmn:encapsulatedLogic>
<dmn:formalParameter name="flight" typeRef="tFlight"/>
<dmn:formalParameter name="rebooked list" typeRef="tPassengerTable"/>
<dmn:literalExpression>
<dmn:text>flight.Capacity > count( rebooked list[ Flight Number = flight.Flight Number ] )</dmn:text>
</dmn:literalExpression>
</dmn:encapsulatedLogic>
<dmn:variable name="has capacity" typeRef="feel:boolean"/>
</dmn:businessKnowledgeModel>
</dmn:definitions>
5.2. DMN support in Kogito
Kogito provides design and runtime support for DMN 1.2 models at conformance level 3, and runtime-only support for DMN 1.1 and 1.3 models at conformance level 3. You can design your DMN models with the Kogito DMN modeler in VSCode or import existing DMN models into your Kogito projects for deployment and execution. DMN 1.1 and 1.3 models are currently not supported in the Kogito DMN modeler.
In addition to all DMN conformance level 3 requirements, Kogito also includes enhancements and fixes to FEEL and DMN model components to optimize the experience of implementing DMN decision services with Kogito. From a platform perspective, DMN models are like any other business asset in Kogito, such as DRL files or spreadsheet decision tables, that you can include in your Kogito project and execute to start your DMN decision services.
5.2.1. Configurable DMN validation in Kogito
By default, the Kogito CodeGen component uses the kogito.decisions.validation=ENABLED
configuration to perform pre-compilation validation of DMN model assets and to perform DMN decision table static analysis.
When this configuration is enabled, Kogito performs the following DMN validations:
-
DMN model files are verified against the DMN specification XSD schema to ensure that the files are valid XML and compliant with the specification.
-
The pre-compilation analysis is performed for the DMN model to ensure that the basic semantic is aligned with the DMN specification.
-
DMN decision tables are statically analyzed for gaps or overlaps and to ensure that the semantic of the decision table follows best practices.
Any DMN validation error causes the Kogito CodeGen build to fail and errors are reported accordingly, as shown in the following example:
You can modify the default DMN validation and DMN decision table analysis behavior to ignore errors during the project build, or you can disable this default behavior completely, as shown in the following examples:
kogito.decisions.validation=ENABLED
kogito.decisions.validation=IGNORE
kogito.decisions.validation=DISABLED
If you enter an unrecognized kogito.decisions.validation configuration flag, all pre-compilation validation features are disabled and the Kogito CodeGen emits related log messages.
|
5.2.2. FEEL enhancements in Kogito
Kogito includes the following enhancements and other changes to FEEL in the current DMN implementation:
-
Space Sensitivity: This DMN implementation of the FEEL language is space insensitive. The goal is to avoid non-deterministic behavior based on the context and differences in behavior based on invisible characters, such as white spaces. This means that for this implementation, a variable named
first name
with one space is exactly the same asfirst name
with two spaces in it. -
List functions
or()
andand()
: The specification defines two list functions namedor()
andand()
. However, according to the FEEL grammar, these are not valid function names, asand
andor
are reserved keywords. This implementation renames these functions toany()
andall()
respectively, in anticipation for DMN 1.2. -
Keyword
in
cannot be used in variable names: The specification defines that any keyword can be reused as part of a variable name, but the ambiguities caused with thefor … in … return
loop prevent the reuse of thein
keyword. All other keywords are supported as part of variable names. -
Keywords are not supported in attributes of anonymous types: FEEL is not a strongly typed language and the parser must resolve ambiguity in name parts of an attribute of an anonymous type. The parser supports reusable keywords as part of a variable name defined in the scope, but the parser does not support keywords in attributes of an anonymous type. For example,
for item in Order.items return Federal Tax for Item( item )
is a valid and supported FEEL expression, where a function namedFederal Tax for Item(…)
can be defined and invoked correctly in the scope. However, the expressionfor i in [ {x and y : true, n : 1}, {x and y : false, n: 2} ] return i.x and y
is not supported because anonymous types are defined in the iteration context of thefor
expression and the parser cannot resolve the ambiguity. -
Support for date and time literals on ranges: According to the grammar rules #8, #18, #19, #34 and #62,
date and time
literals are supported in ranges (pages 110-111). Chapter <IP_ADDRESS> on page 114, on the other hand, contradicts the grammar and says they are not supported. This implementation chose to follow the grammar and supportdate and time
literals on ranges, as well as extend the specification to support any arbitrary expression (see extensions below). -
Invalid time syntax: Chapter <IP_ADDRESS>.4 on page 112 and bullet point about
time
on page 131 both state that thetime
string lexical representation follows the XML Schema Datatypes specification as well as ISO 8601. According to the XML Schema specification (https://www.w3.org/TR/xmlschema-2/#time), the lexical representation of a time follows the patternhh:mm:ss.sss
without any leading character. The DMN specification uses a leading "T" in several examples, that we understand is a typo and not in accordance with the standard. -
Support for scientific and hexadecimal notations: This implementation supports scientific and hexadecimal notation for numbers. For example,
1.2e5
(scientific notation),0xD5
(hexadecimal notation). -
Support for expressions as end points in ranges: This implementation supports expressions as endpoints for ranges. For example,
[date("2016-11-24")..date("2016-11-27")]
-
Support for additional types: The specification only defines the following as basic types of the language:
-
number
-
string
-
boolean
-
days and time duration
-
years and month duration
-
time
-
date and time
For completeness and orthogonality, this implementation also supports the following types:
-
context
-
list
-
range
-
function
-
unary test
-
-
Support for unary tests: For completeness and orthogonality, unary tests are supported as first class citizens in the language. They are functions with an implicit single parameter and can be invoked in the same way as functions. For example,
UnaryTestAsFunction.feel{ is minor : < 18, Bob is minor : is minor( bob.age ) }
-
Support for additional built-in functions: The following additional functions are supported:
-
now()
: Returns the current local date and time. -
today()
: Returns the current local date. -
decision table()
: Returns a decision table function, although the specification mentions a decision table. The function on page 114 is not implementable as defined. -
string( mask, p… )
: Returns a string formatted as per the mask. See Java String.format() for details on the mask syntax. For example,string( "%4.2f", 7.1298 )
returns the string"7.12"
.
-
-
Support for additional date and time arithmetics: Subtracting two dates returns a day and time duration with the number of days between the two dates, ignoring daylight savings. For example,
DateArithmetic.feeldate( "2017-05-12" ) - date( "2017-04-25" ) = duration( "P17D" )
5.2.3. DMN model enhancements in Kogito
Kogito includes the following enhancements to DMN model support in the current DMN implementation:
-
Support for types with spaces on names: The DMN XML schema defines type refs such as QNames. The QNames do not allow spaces. Therefore, it is not possible to use types like FEEL
date and time
,days and time duration
oryears and months duration
. This implementation does parse such typerefs as strings and allows type names with spaces. However, in order to comply with the XML schema, it also adds the following aliases to such types that can be used instead:-
date and time
=dateTime
-
days and time duration
=duration
ordayTimeDuration
-
years and months duration
=duration
oryearMonthDuration
Note that, for the "duration" types, the user can simply use
duration
and the decision engine will infer the proper duration, eitherdays and time duration
oryears and months duration
.
-
-
Lists support heterogeneous element types: Currently this implementation supports lists with heterogeneous element types. This is an experimental extension and does limit the functionality of some functions and filters. This decision will be re-evaluated in the future.
-
TypeRef link between Decision Tables and Item Definitions: On decision tables/input clause, if no values list is defined, the decision engine automatically checks the type reference and applies the allowed values check if it is defined.
5.3. Creating and editing DMN models in the Kogito DMN modeler
You can use the Kogito DMN modeler in VSCode to design DMN decision requirements diagrams (DRDs) and define decision logic for a complete and functional DMN decision model. Kogito provides design and runtime support for DMN 1.2 models at conformance level 3, and includes enhancements and fixes to FEEL and DMN model components to optimize the experience of implementing DMN decision services with Kogito. Kogito also provides runtime-only support for DMN 1.1 and 1.3 models at conformance level 3. DMN 1.1 and 1.3 models are currently not supported in the Kogito DMN modeler.
-
VSCode 1.46.0 or later is installed.
-
The Kogito Bundle VSCode extension is installed and enabled in your VSCode IDE. For information about enabling the VSCode extension, see Installing the Kogito VSCode extension bundle without the Kogito Business Modeler Hub.
-
You have created a Kogito project and have included any Java objects required for your Kogito service. For information about creating a project, see Creating and running your first Kogito services.
-
In your VSCode IDE, create or import a DMN file in the relevant folder of your Kogito project, typically in
src/main/resources
.For a new DMN file, you can also enter dmn.new
in a web browser to design your decision model in the Kogito online DMN modeler. When you finish creating your decision model, you can click Download in the online modeler page to import your DMN file into your Kogito project. -
Open the new or imported DMN file to view the decision requirements diagram (DRD) in the Kogito DMN modeler.
If the DRD does not open in the Kogito DMN modeler, ensure that you have installed and enabled the Kogito Bundle VSCode extension.
If the Kogito DMN modeler opens only the XML source of the DMN file and displays an error message, review the reported errors and the DMN model file to ensure that all DMN elements are correctly defined.
-
Begin adding components to your new or imported DRD by clicking and dragging one of the DMN nodes from the left toolbar:
Figure 90. Adding DRD componentsThe following DRD components are available:
-
Decision: Use this node for a DMN decision, where one or more input elements determine an output based on defined decision logic.
-
Business knowledge model: Use this node for reusable functions with one or more decision elements. Decisions that have the same logic but depend on different sub-input data or sub-decisions use business knowledge models to determine which procedure to follow.
-
Knowledge source: Use this node for external authorities, documents, committees, or policies that regulate a decision or business knowledge model. Knowledge sources are references to real-world factors rather than executable business rules.
-
Input data: Use this node for information used in a decision node or a business knowledge model. Input data usually includes business-level concepts or objects relevant to the business, such as loan applicant data used in a lending strategy.
-
Text annotation: Use this node for explanatory notes associated with an input data node, decision node, business knowledge model, or knowledge source.
-
Decision service: Use this node to enclose a set of reusable decisions implemented as a decision service for invocation. A decision service can be used in other DMN models and can be invoked from an external application or a BPMN business process.
-
-
In the DMN modeler canvas, double-click the new DRD node to enter an informative node name.
-
If the node is a decision or business knowledge model, select the node to display the node options and click the Edit icon to open the DMN boxed expression editor to define the decision logic for the node:
Figure 91. Opening a new decision node boxed expressionFigure 92. Opening a new business knowledge model boxed expressionBy default, all business knowledge models are defined as boxed function expressions containing a literal FEEL expression, a nested context expression of an external JAVA or PMML function, or a nested boxed expression of any type.
For decision nodes, you click the undefined table to select the type of boxed expression you want to use, such as a boxed literal expression, boxed context expression, decision table, or other DMN boxed expression.
Figure 93. Selecting the logic type for a decision nodeFor business knowledge models, you click the upper-left function cell to select the function type, or right-click the function value cell, select Clear, and select a boxed expression of another type.
Figure 94. Selecting the function or other logic type for a business knowledge model -
In the selected boxed expression editor for either a decision node (any expression type) or business knowledge model (function expression), click the applicable table cells to define the table name, variable data types, variable names and values, function parameters and bindings, or FEEL expressions to include in the decision logic.
You can right-click cells for additional actions where applicable, such as inserting or removing table rows and columns or clearing table contents.
The following is an example decision table for a decision node that determines credit score ratings based on a defined range of a loan applicant’s credit score:
Figure 95. Decision node decision table for credit score ratingThe following is an example boxed function expression for a business knowledge model that calculates mortgage payments based on principal, interest, taxes, and insurance (PITI) as a literal expression:
Figure 96. Business knowledge model function for PITI calculation -
After you define the decision logic for the selected node, click Back to MODEL_NAME to return to the DRD view.
-
For the selected DRD node, use the available connection options to create and connect to the next node in the DRD, or click and drag a new node onto the DRD canvas from the left toolbar.
The node type determines which connection options are supported. For example, an Input data node can connect to a decision node, knowledge source, or text annotation using the applicable connection type, whereas a Knowledge source node can connect to any DRD element. A Decision node can connect only to another decision or a text annotation.
The following connection types are available, depending on the node type:
-
Information requirement: Use this connection from an input data node or decision node to another decision node that requires the information.
-
Knowledge requirement: Use this connection from a business knowledge model to a decision node or to another business knowledge model that invokes the decision logic.
-
Authority requirement: Use this connection from an input data node or a decision node to a dependent knowledge source or from a knowledge source to a decision node, business knowledge model, or another knowledge source.
-
Association: Use this connection from an input data node, decision node, business knowledge model, or knowledge source to a text annotation.
Figure 97. Connecting credit score input to the credit score rating decision -
-
Continue adding and defining the remaining DRD components of your decision model and save the completed DRD.
The following is an example DRD for a loan prequalification decision model:
Figure 98. Completed DRD for loan prequalificationThe following is an example DRD for a phone call handling decision model using a reusable decision service: