Skip to Content
Author's profile photo Frank Schuler

SAP HANA Rules Framework End-to-End Tutorial

Inspired by the excellent series of SAP HANA Rules Framework by the SAP HANA Academy YouTube videos listed by Denys van Kempen, and because I did not have the banking model available referenced in those videos, I decided to start my own SAP HANA Rules Framework 1.0 SPS 07 proof of concept implementation.

This blog describes my steps from installing the SAP HANA Rules Framework 1.0 SPS 07 Patch Level 1 and configuring it until creating a HANA Rule and executing a HANA Rule Service with varying HANA Rule Conditions in the end. For further details please refer to SAP Note 2259199 – Release-Informationen zu SAP HANA Rules Framework 1.0 SPS07 and to the SAP HANA Rules Framework’s official documentation on SAP Service Marketplace.

The SAP HANA Rules Framework 1.0 SPS 07 can be downloaded from SAP Service Marketplace:

SMP.png

At the time of this blog, SPS 07 Patch Level 1 was the latest available version:

HCORULEFW07P_1.png

Please be aware that SAP HANA Rules Framework 1.0 SPS 07 requires SAP HANA SPS 11. For this blog, I have been using the SAP HANA Database Revision 111. However please be aware, that at the time of this blog, there has been no SAP HANA Datacenter Service Point released for HANA SPS 11 yet, so at the time of this blog, you should try this in a sandbox environment only. Please check SAP Note 2021789 – SAP HANA Revision and Maintenance Strategy, whether this is still the case when you read this.

After extracting the ZIP archive, I install the package with the HANA Application Lifecycle Management Delivery Units Import functionality:

Import Delivery Unit.png

After confirming the import of the Delivery Unit:

Confirm Import of Delivery Unit.png

The imports starts and runs for a little while. Once completed you get a green light and we are ready to proceed:

HCO_RULE_FW.png

Next, back in HANA Studio, you have to create a user called HRF_TECH_USER and grant this user the following, to enable rule service consumption:

  • sap.hrf::AllPrivilegesForTechnicalUser application privilege
  • sap.hrf.role.model::HRF_TECH_ROLE role

Also, you would have to grant your user a series of HANA Rules Framework Roles:

Granted Roles.png

With that preparation we can configure the HANA Rules Framework via REST API. Please configure basic authentication with your user, that you granted the roles above. As a result, you are rewarded with a success message:

HRF Technical Configuration success.png

And subsequently with access to the Fiori Launch Pad of the SAP HANA Rules Framework at:

http://<full_domain_name>:80<instance_number>/sap/hana/uis/clients/ushell-app/shells/fiori/FioriLaunchpad.html?siteId=sap.hrf.ui|app|app

Launch Pad.png

With the configuration in the bag, we next deploy the SAP HANA Rules Framework Modelling Tools at:

http://<hostname>:80<instance_number>/sap/hrf/updatesite

HANA Rules Framework Tools.png

After confirming the license agreement the software gets installed and you will have to restart SAP HANA Studio.

Next we build a small Point of Sales data model as the basis for our HANA Rules. You find the SQL scripts for these tables and their contents in the appendix at the end of this blog:

Tables.png

Please do not forget to grant both users _SYS_REPO and HRF_TECH_USER SELECT Privileges with Grant Option to the schema of your user. These are needed for the creation and execution of the Rules Service respectively:

Priviledges.png

Now we create a new XS Project and within that a new Vocabulary based on the tables above:

/wp-content/uploads/2016/03/hpvocabulary_900151.png

For this we join:

  • CUSTOMER.ID to SOHEADER.DEBITOR
  • SOHEADER.NUMBER to SOITEM.PO
  • SOITEM.ARTICLE to ARTICLE.PART

In addition we activate (marked with an Orange light):

  • CUSTOMER.NAME
  • CUSTOMER.SEGMENT
  • SOHEADER.TOTAL
  • ARTICLE.CATEGORY

Outline.png

To finish our vocabulary, we create an Output Type:

Edit Output.png

Now we got the basis to create our first HANA Rule. In the Fiori Launch Pad of the SAP HANA Rules Framework chose Rules – Mange all rules and create a new HANA Rule:

Segmentation.png

Then add the following conditions. Type forward help will help you immensely with this, especially for the joined condition Category over three intermediate tables:

Edit Conditions.png

Finally Add Output Customer and provide conditions as follows:

  • Conditions: SEGMENT of the CUSTOMER = ‘Y’
  • CATEGORY of the PART of the PO of the DEBITOR of the CUSTOMER = ‘G’
  • Outputs: Customer NAME of the CUSTOMER

Rule.png

Now Activate the Rule and select Rule Services from the Fiori Launch Pad of the SAP HANA Rules Framework and create a new Rules Service as follows:

Rule Service.png

Once you save this Rule Service and Test run it, you get two hits as expected, i.e. the customers in Segment = ‘Y’ and at least one purchase of a product in Category = ‘G’:

Test Results.png

Now you can play with the Rule Conditions and check-out the respective Test Results. If you for example changed the Category Condition to ‘P’ and Activate it:

Activate.png

You would only get the one expected Test Result back:

Faigle.png

And when further changing the Segment Condition to ‘X’ and Activate it:

Rule Builder.png

You get back the one customer with Segment = ‘X’ and a product in Category = ‘P’:

Frehn.png

Appendix

These are the SQL scripts to create the Point of Sales data model used in this blog. Schema USER will have to be replaced with your user schema:

CREATE COLUMN TABLE "USER"."CUSTOMER" ("ID" INTEGER CS_INT NOT NULL ,
	 "NAME" VARCHAR(8),
	 "SEGMENT" VARCHAR(1),
	 PRIMARY KEY ("ID")) UNLOAD PRIORITY 5 AUTO MERGE ;
	 
INSERT INTO "USER"."CUSTOMER" VALUES(1,'Faigle','Y');

INSERT INTO "USER"."CUSTOMER" VALUES(2,'Frehn','X');

INSERT INTO "USER"."CUSTOMER" VALUES(3,'Schuler','Y');
	 
CREATE COLUMN TABLE "USER"."SOHEADER" ("NUMBER" INTEGER CS_INT NOT NULL ,
	 "DEBITOR" INTEGER CS_INT,
	 "TOTAL" DECIMAL(5,2) CS_FIXED,
	 PRIMARY KEY ("NUMBER")) UNLOAD PRIORITY 5 AUTO MERGE ;
	 
INSERT INTO "USER"."SOHEADER" VALUES(1,1,70);

INSERT INTO "USER"."SOHEADER" VALUES(2,2,50);

INSERT INTO "USER"."SOHEADER" VALUES(3,3,30);

CREATE COLUMN TABLE "USER"."SOITEM" ("PO" INTEGER CS_INT,
	 "ARTICLE" INTEGER CS_INT,
	 "COUNT" INTEGER CS_INT,
	 "AMOUNT" DECIMAL(5,2) CS_FIXED) UNLOAD PRIORITY 5 AUTO MERGE ;
	 
INSERT INTO "USER"."SOITEM" VALUES(1,1,1,50);

INSERT INTO "USER"."SOITEM" VALUES(1,2,2,20);

INSERT INTO "USER"."SOITEM" VALUES(2,1,1,50);

INSERT INTO "USER"."SOITEM" VALUES(3,2,3,30);

CREATE COLUMN TABLE "USER"."ARTICLE" ("PART" INTEGER CS_INT NOT NULL ,
	 "DESCRIPTION" VARCHAR(10),
	 "PRICE" DECIMAL(5,2) CS_FIXED,
	 "CATEGORY" VARCHAR(1),
	 PRIMARY KEY ("PART")) UNLOAD PRIORITY 5 AUTO MERGE ;
	 
INSERT INTO "USER"."ARTICLE" VALUES(1,'Keyboard',50,'P');

INSERT INTO "USER"."ARTICLE" VALUES(2,'USB Stick',10,'G');

Assigned Tags

      17 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Bing Liu
      Bing Liu

      Dear Frank,

      Many thanks for your wonderful blog.

      Author's profile photo Bing Liu
      Bing Liu

      I followed the steps shown in the blog to install HRF. But I met an error when I tried to open:

      <full_domain_name>:80<instance_number>/sap/hana/uis/clients/ushell-app/shells/fiori/FioriLaunchpad.html?siteId=sap.hrf.ui|app|app2


      Error message: Failure-Unable to load groups.


      It worked after I changed the url as:

      <full_domain_name>:80<instance_number>/sap/hana/uis/clients/ushell-app/shells/fiori/FioriLaunchpad.html?siteId=sap.hrf.ui|app|app


      Author's profile photo Frank Schuler
      Frank Schuler
      Blog Post Author

      Hello Bing,

      have you assigned your user role sap.hrf.role.model::HrfAdmin?

      Best regards

      Frank

      Author's profile photo Randy Middleton
      Randy Middleton

      Thx for your wonderful blog.  I will execute in my test dev system, week of 21-Mar-2016.  I will also update with my success. Thanks again for your specific details.  Much Appriciated .

      Author's profile photo asif hussain
      asif hussain

      Thank you very much Frank for Clear Explanation

      Could it possible to provide the Json file of above explained example ,want to check how it has created as I don't have HRF GUI so planning to incorporate using file and trying to import the Json file.

      email id :asifhussain.p@gmail.com

      Thanks,
      Asif

       

      Author's profile photo Frank Schuler
      Frank Schuler
      Blog Post Author

      Hello Asif,

      these are the respective HRF artefacts:

      pos.hprvocabulary:

      {
          "dataObjects":[
              {
                  "name":"CUSTOMER",
                  "description":"FSCHULER-CUSTOMER",
                  "attributes":[
                      {
                          "name":"ID",
                          "description":"ID",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"ID"
                          }
                      },
                      {
                          "name":"NAME",
                          "description":"NAME",
                          "dataType":"VARCHAR",
                          "businessDataType":"String",
                          "sourceType":"Data",
                          "size":"8",
                          "dataMapping":{
                              "column":"NAME"
                          }
                      },
                      {
                          "name":"SEGMENT",
                          "description":"SEGMENT",
                          "dataType":"VARCHAR",
                          "businessDataType":"String",
                          "sourceType":"Data",
                          "size":"1",
                          "dataMapping":{
                              "column":"SEGMENT"
                          }
                      }
                  ],
                  "associations":[
                      {
                          "name":"DEBITOR",
                          "target":"SOHEADER",
                          "cardinality":"OneToOne",
                          "attributeMappings":[
                              {
                                  "source":"ID",
                                  "target":"DEBITOR"
                              }
                          ]
                      }
                  ],
                  "mappingInfo":{
                      "schema":"FSCHULER",
                      "name":"CUSTOMER",
                      "type":"Table"
                  },
                  "layout":{
                      "location":{
                          "x":"70",
                          "y":"30"
                      }
                  }
              },
              {
                  "name":"SOHEADER",
                  "description":"FSCHULER-SOHEADER",
                  "attributes":[
                      {
                          "name":"DEBITOR",
                          "description":"DEBITOR",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"DEBITOR"
                          }
                      },
                      {
                          "name":"NUMBER",
                          "description":"NUMBER",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"NUMBER"
                          }
                      },
                      {
                          "name":"TOTAL",
                          "description":"TOTAL",
                          "dataType":"DECIMAL",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "size":"3,2",
                          "dataMapping":{
                              "column":"TOTAL"
                          }
                      }
                  ],
                  "associations":[
                      {
                          "name":"PO",
                          "target":"SOITEM",
                          "cardinality":"OneToOne",
                          "attributeMappings":[
                              {
                                  "source":"NUMBER",
                                  "target":"PO"
                              }
                          ]
                      }
                  ],
                  "mappingInfo":{
                      "schema":"FSCHULER",
                      "name":"SOHEADER",
                      "type":"Table"
                  },
                  "layout":{
                      "location":{
                          "x":"310",
                          "y":"30"
                      }
                  }
              },
              {
                  "name":"SOITEM",
                  "description":"FSCHULER-SOITEM",
                  "attributes":[
                      {
                          "name":"PO",
                          "description":"PO",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"PO"
                          }
                      },
                      {
                          "name":"ARTICLE",
                          "description":"ARTICLE",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"ARTICLE"
                          }
                      }
                  ],
                  "associations":[
                      {
                          "name":"PART",
                          "target":"ARTICLE",
                          "cardinality":"OneToOne",
                          "attributeMappings":[
                              {
                                  "source":"ARTICLE",
                                  "target":"PART"
                              }
                          ]
                      }
                  ],
                  "mappingInfo":{
                      "schema":"FSCHULER",
                      "name":"SOITEM",
                      "type":"Table"
                  },
                  "layout":{
                      "location":{
                          "x":"550",
                          "y":"30"
                      }
                  }
              },
              {
                  "name":"ARTICLE",
                  "description":"FSCHULER-ARTICLE",
                  "attributes":[
                      {
                          "name":"PART",
                          "description":"PART",
                          "dataType":"INTEGER",
                          "businessDataType":"Number",
                          "sourceType":"Data",
                          "dataMapping":{
                              "column":"PART"
                          }
                      },
                      {
                          "name":"CATEGORY",
                          "description":"CATEGORY",
                          "dataType":"VARCHAR",
                          "businessDataType":"String",
                          "sourceType":"Data",
                          "size":"1",
                          "dataMapping":{
                              "column":"CATEGORY"
                          }
                      }
                  ],
                  "associations":[],
                  "mappingInfo":{
                      "schema":"FSCHULER",
                      "name":"ARTICLE",
                      "type":"Table"
                  },
                  "layout":{
                      "location":{
                          "x":"790",
                          "y":"30"
                      }
                  }
              }
          ],
          "outputs":[
              {
                  "name":"Customer",
                  "description":"Customer",
                  "inputParams":[
                      {
                          "name":"Customer",
                          "dataType":"VARCHAR",
                          "size":"8"
                      }
                  ]
              }
          ]
      }

      Segmentation.hprrule:

      {
        "description": "Check Customer Segment and Product Category",
        "ruleBody": {
          "type": "decisionTable",
          "content": {
            "headers": [
              {
                "colID": "id-1457012402797-49",
                "expression": "SEGMENT of the CUSTOMER",
                "alias": "Segment",
                "type": "condition"
              },
              {
                "type": "condition",
                "expression": "CATEGORY of the PART of the PO of the DEBITOR of a CUSTOMER",
                "alias": "Category",
                "colID": "id-1457018668865-111"
              },
              {
                "expression": "",
                "name": "Customer",
                "type": "output",
                "businessDataType": "String",
                "isCollection": false,
                "colID": "id-1457012492442-59"
              }
            ],
            "rows": [
              {
                "rowID": "id-1457012402797-50",
                "row": [
                  {
                    "colID": "id-1457012402797-49",
                    "content": "= 'X'",
                    "span": 1
                  },
                  {
                    "colID": "id-1457018668865-111",
                    "content": "= 'P'",
                    "span": 1
                  },
                  {
                    "colID": "id-1457012492442-59",
                    "content": "NAME of the CUSTOMER",
                    "span": 1
                  }
                ]
              }
            ]
          },
          "hitPolicy": "allMatch"
        },
        "status": "Active",
        "vocabulary": "hrf::pos",
        "output": "Customer",
        "conversionFlagsMap": {
          "isValueListConverted": true
        }
      }

      Discount.hprruleservice:

      {
        "description": "Discount Rules",
        "vocabulary": "hrf::pos",
        "output": "Customer",
        "readOnly": true,
        "resultView": "resultViewOnly",
        "ruleAssignment": "Automatic",
        "executionContext": {
          "dataObject": {
            "name": "CUSTOMER",
            "keys": [
              "SEGMENT"
            ]
          }
        },
        "conversionFlagsMap": {
          "isValueListConverted": true
        }
      }
      Author's profile photo asif hussain
      asif hussain

       

      Thank you very much Frank

      Author's profile photo Noam Gilady
      Noam Gilady

      Hi Frank,

      Welldone! This is an excellent blog!

      Noam Gilady,
      Senior Product Owner
      Cloud Exp NW & Rules - HRF

      Author's profile photo Deshpande Hrishikesh
      Deshpande Hrishikesh

      Hi Frank

      We have deployed SAP HRF but getting this error-

      {"code":"10001","message":"HRF Technical Configuration failure","output":{},"details":[{"subject":"hrfInstallation.xsjs","messages":[{"code":"2956","severity":"error","description":"Mode \\#GET is not supported"}]}]}

      Could you please tell me how to execute script with REST api.

       

      BR,

      Hrishikesh

      Author's profile photo Frank Schuler
      Frank Schuler
      Blog Post Author

      Hello Hrishikesh,

      You have to send the configuration information to the API as a POST request. From the error message you receive, I gather that you are using a GET request, which does not work.

      Best regards

      Frank

      Author's profile photo Mayank Seth
      Mayank Seth

      any resolution of this

      hrfInstallation.xsjs","messages":[{"code":"2956" ?? am getting same error as Hrishikesh
      Author's profile photo Deshpande Hrishikesh
      Deshpande Hrishikesh

      Hi Frank

      Thank you so much for your help.

      It worked !!!

       

      BR,

      Hrishikesh

      Author's profile photo Former Member
      Former Member

      Hi Frank Schuler,

      Could you please tell me, How can I implement HRF to HCP's IOT module ?

      Regards

      Kafi

      Author's profile photo Frank Schuler
      Frank Schuler
      Blog Post Author

      Hello Kafi,

      There are quite a few options how to consume a rule service. Please check section 6.4.2 Consuming a Rule Service in the SAP HANA Rules Framework 1.0 SPS09 Dev. & Implem. Guide.

      Best regards

      Frank

      Author's profile photo Ashokkumar Narasimhan
      Ashokkumar Narasimhan

      Hi Frank

      Excellent Blog.

      Thanks

      Ashok

      Author's profile photo Sanampreet Singh
      Sanampreet Singh

      Hi Frank,

      Once a Rule service is created, I can run it using "Run" button present in the Fiori Launchpad of SAP HRF.

      But how can I call/run this service from some other application or xsjs service or procedure?

      Because every time you won't call it manually. Right?

       

      Best Regards,

      Sanampreet Singh

      Author's profile photo Former Member
      Former Member

      Hi Frank,

      Can we schedule HANA Rule Service? Instead of running it from Rule service Launchpad.

      We can use created procedure and view by rule service and create XSJobs and schedule it.

      If SAP provides any functionality for this.

       

      Regards,

      Kalpan