Name

global.CMDBDynamicIREMLInterface

Description

No description available

Script

var CMDBDynamicIREMLInterface = Class.create();
CMDBDynamicIREMLInterface.prototype = {

  _CMDB_DYNAMIC_IRE_MATCH: "cmdb_dynamic_ire_match",
  _LOG_PROPERTY: "glide.identification_engine.ire_dynamic.log.level",
  _ML_SOLUTION: "ml_solution",
  _SOLUTION_NAME: "solution_name",
  _ML_MODEL_ARTIFACT: "ml_model_artifact",
  _TABLE_REF_SOLUTION: "solution",
  _MODEL_ID: "model_id",
  _DOT: ".",
  _TEXTNODE: '#text',
  _VERSION: "version",
  _ACTIVE: "active",
  _SYS_CREATED_ON: 'sys_created_on',
  _XML_TAG_SOLUTION_NAME: "solutionName",
  _XML_TAG_ALIAS_NAMES: "actualColumnNameToAliasColumnName",
  _XML_TAG_CLASSIFIER: "m__Classifier",
  _XML_TAG_NOMINAL_TO_BINARY: "m__NominalToBinary",
  _XML_TAG_OUTPUT_FORMAT: "m__OutputFormat",
  _XML_TAG_ATTRIBTUES: "m__Attributes",
  _XML_TAG_TYPE: "m__Type",
  _XML_TAG_NAME: "m__Name",
  _XML_TAG_INDEX: "m__Index",
  _XML_TAG_MODEL_WIGHTS: "w",
  _XML_TAG_ALIAS_CLASS_VALUE_TO_ACTUAL_VALUE: "aliasClassValueToActualClassValue",
  _XML_TAG_LABEL: "label",
  _XML_TAG_ATTRIBUTE_INFO: "m__AttributeInfo",
  _XML_TAG_HASH_TABLE: "m__Hashtable",
  _XML_TAG_STRING: "string",
  _XML_TAG_INT: "int",
  _XML_TAG_BIAS_CLASS_AND_PROBABILITY: "biasClassAndProbability",
  _BIAS: "bias",
  _NO_MATCH: "0",
  _MATCH: "1",

  initialize: function(logProperty) {

      if (JSUtil.nil(logProperty))
          logProperty = this._LOG_PROPERTY;

      this.log = new GSLog(logProperty, this.type);
  },

  /*
   * Return the model metadate of the trained model
   * @param mlSolutionName the soution for which the weights are required
   * @param mlSolutionVersion the solution version for which the weights are required
   * @return weights {status: "SUCCESS", weights: "{["feature_name":"weight"]}"}
   */

  getModelMetaData: function(mlSolutionName, mlSolutionVersion) {
      var result = {};
      this._invalid.mlSolutionName = mlSolutionName;
      this._invalid.result = result;
      this._invalid.message = 'There was an issue while loading the model file from the ML platform tables for solution {0} and soutionVersion {1}';
      this._invalid.log = this.log;

      result.status = "SUCCESS";
      try {

          var gr = new GlideRecord(this._ML_SOLUTION);
          gr.addQuery(this._SOLUTION_NAME, mlSolutionName);
          gr.query();
          if (!gr.next()) {
              result.status = "FAILURE";
              result.statusCode = "solution_unavailable";
              return JSON.stringify(result);
          }

          this.log.logInfo('CMDBDynamicIREMLInterface::getModelMetaData The solution: ' + mlSolutionName + ' is available, successfully found.');
          var solutionSysId = gr.getUniqueValue();

          var modelFeatureNamesXML = this._getArtifactStream(solutionSysId, '0.gz', mlSolutionVersion);
          if (this._invalid.node(modelFeatureNamesXML, 'model_features_xml_was_null'))
              return JSON.stringify(result);

          this.log.logInfo('CMDBDynamicIREMLInterface::getModelMetaData The modelFeatures XML was successfully loaded: ' + modelFeatureNamesXML);

          var weightsXML = this._getArtifactStream(solutionSysId, mlSolutionName + '.gz', mlSolutionVersion);
          if (this._invalid.node(weightsXML, 'model_features_weights_xml_was_null'))
              return JSON.stringify(result);

          this.log.logInfo('CMDBDynamicIREMLInterface::getModelMetaData The modelFeatureWeights XML was successfully loaded: ' + weightsXML);

          var weightsResponse = this._extractWeightsFromModelFiles(mlSolutionName, modelFeatureNamesXML, weightsXML);
          if (this._invalid.node(weightsResponse, 'model_features_weights_extraction_failed'))
              return JSON.stringify(result);

          //check if the  status is Failure and update the main result response object
          if (this._invalid_condition(weightsResponse.status == 'FAILURE', weightsResponse.statusCode))
              return JSON.stringify(result);

          if (weightsResponse.status == 'SUCCESS')
              result.weights = weightsResponse;

      } catch (ex) {
          this.log.logErr('CMDBDynamicIREMLInterface::getModelMetaData msg: ' + ex);
      }
      return JSON.stringify(result);
  },

  _invalid: {
      mlSolutionName: '',
      result: {},
      message: '',
      log: {},
      _log: function(code) {
          this.result.status = 'FAILURE';
          this.result.statusCode = code;
          this.log.logErr(this.formatMessage(this.message, [this.mlSolutionName, code]));
      },
      iterator: function(iterator, code) {
          return this.condition(gs.nil(iterator) || !iterator.hasNext(), code);
      },
      node: function(node, code) {
          return this.condition(gs.nil(node), code);
      },
      condition: function(condition, code) {
          if (condition) {
              this._log(code);
              return true;
          }
          return false;
      },
      formatMessage: function(str, args) {
          this._replaceExpr = this._replaceExpr || [];

          for (var i = 0; i < args.length; i++) {
              if (i >= this._replaceExpr.length)
                  this._replaceExpr[i] = new RegExp('\\{' + i + '\\}', 'gi');

              str = str.replace(this._replaceExpr[i], args[i]);
          }
          return str;
      },
  },

  /*
  	@param mlSolutionName : The solution Name of the model
  	@param modelFeatureNamesXML : featureNames XML
  	@param weightsXML: the weights XML
   */
  _extractWeightsFromModelFiles: function(mlSolutionName, modelFeatureNamesStream, weightsStream) {
      var weights = {};
      this._invalid.mlSolutionName = mlSolutionName;
      this._invalid.result = weights;
      this._invalid.message = 'There was an issue while loading the model weights from the ML platform tables. {0}, error {1}';
      this._invalid.log = this.log;

      try {

          var featuresDoc = sn_cmdb.DynamicIREScriptableAPI.getScopedXMLDocument2(modelFeatureNamesStream);
          var root = featuresDoc.getDocumentElement().getNodeName();

          var solutionNameTag = featuresDoc.getFirstNode('/' + root + '/' + this._XML_TAG_SOLUTION_NAME);
          if (this._invalid.node(solutionNameTag, 'solution_name_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
              return weights;

          var solutionName = solutionNameTag.getTextContent();
          if (this._invalid.condition(solutionName != mlSolutionName, 'solution_name_passed_does_not_match_with_model_meta_data'))
              return weights;

          var aliasTag = featuresDoc.getFirstNode('/' + root + '/' + this._XML_TAG_ALIAS_NAMES);
          if (this._invalid.node(aliasTag, 'alias_name_tag_not_present_check_with_ml_platform'))
              return weights;

          var aliasTagChildren = aliasTag.getChildNodeIterator();
          if (this._invalid.iterator(aliasTagChildren, 'alias_name_tag_does_not_have_children_check_with_ml_platform'))
              return weights;

          var columnMap = {};
          var aliasTagChildNode = null;
          var stringNodes = null;
          var i = 0;
          while (aliasTagChildren.hasNext() && (aliasTagChildNode = aliasTagChildren.next()) != null) {
              if (this._invalid.node(aliasTagChildNode, 'entry_tag_does_not_exists_for_item ' + (i + 1) + '_check_with_ml_platform'))
                  return weights;

              if (aliasTagChildNode.getNodeName() == this._TEXTNODE)
                  continue;
              i++;

              stringNodes = aliasTagChildNode.getChildNodeIterator();
              if (this._invalid.iterator(stringNodes, 'entry_tag_does_not_have_children_for_item' + i + '_check_with_ml_platform'))
                  return weights;

              var item0, item1;
              while (stringNodes.hasNext() && (item0 = stringNodes.next()) != null && item0.getNodeName() == this._TEXTNODE);
              while (stringNodes.hasNext() && (item1 = stringNodes.next()) != null && item1.getNodeName() == this._TEXTNODE);
              if (this._invalid.condition((gs.nil(item0) || gs.nil(item1) ||
                      gs.nil(item0.getTextContent()) || gs.nil(item1.getTextContent()) ||
                      item0.getTextContent().trim() == '' || item1.getTextContent().trim() == ''), 'string_tag_does_not_have_value_for_item_check_with_ml_platform'))
                  return weights;

              columnMap[item1.getTextContent()] = item0.getTextContent();
          }


          var weightsDoc = new sn_cmdb.DynamicIREScriptableAPI.getScopedXMLDocument2(weightsStream);
          root = weightsDoc.getDocumentElement().getNodeName();
          var xpath = '/' + root + '/wekaClassifier/' + this._XML_TAG_CLASSIFIER + '/' + this._XML_TAG_CLASSIFIER + '/' + this._XML_TAG_CLASSIFIER;

          var labelTag = weightsDoc.getFirstNode(xpath + '/m__Model/' + this._XML_TAG_LABEL);
          if (this._invalid.node(labelTag, 'label_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
              return weights;

          var intNodesOflabelTag = labelTag.getChildNodeIterator();
          if (this._invalid.iterator(intNodesOflabelTag, 'label_tag_does_not_have_children_check_with_ml_platform'))
              return weights;

          var labelTagIntNode = null;
          var count = 0;
          while (intNodesOflabelTag.hasNext() && (labelTagIntNode = intNodesOflabelTag.next()) != null) {
              if (labelTagIntNode.getNodeName() == this._TEXTNODE)
                  continue;

              columnMap['label_index_' + count] = labelTagIntNode.getTextContent();
              count++;
          }

          var attributesTag = weightsDoc.getFirstNode(xpath + '/' + this._XML_TAG_NOMINAL_TO_BINARY + '/' + this._XML_TAG_OUTPUT_FORMAT + '/' + this._XML_TAG_ATTRIBTUES);
          if (this._invalid.node(attributesTag, 'm__Attributes_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
              return weights;

          var wekaAttributeList = attributesTag.getChildNodeIterator();
          if (this._invalid.iterator(wekaAttributeList, 'm__Attributes_tag_does_not_have_children_weka.core.Attribute_missing_check_with_ml_platform'))
              return weights;

          var indexToFeatureNameMap = {},
              wekaAttribute;
          while (wekaAttributeList.hasNext() && (wekaAttribute = wekaAttributeList.next()) != null) {

              if (wekaAttribute.getNodeName() == this._TEXTNODE)
                  continue;

              var wekaAttributeChildren = wekaAttribute.getChildNodeIterator();
              if (gs.nil(wekaAttributeChildren) || !wekaAttributeChildren.hasNext())
                  continue;

              var wekaAttributeChild, childData = {};
              while (wekaAttributeChildren.hasNext() && (wekaAttributeChild = wekaAttributeChildren.next()) != null) {

                  if (wekaAttributeChild.getNodeName() == this._TEXTNODE)
                      continue;

                  if (wekaAttributeChild.getNodeName() == this._XML_TAG_ATTRIBUTE_INFO) {
                      childData[this._XML_TAG_ATTRIBUTE_INFO] = true;

                      var attributeInfoChildren = wekaAttributeChild.getChildNodeIterator();
                      if (this._invalid.iterator(attributeInfoChildren, 'm__AttributeInfo_tag_does_not_have_children_check_with_ml_platform'))
                          return weights;

                      var hashtableTag;
                      while (attributeInfoChildren.hasNext() && (hashtableTag = attributeInfoChildren.next()).getNodeName() != this._XML_TAG_HASH_TABLE);
                      if (this._invalid.condition(hashtableTag.getNodeName() != this._XML_TAG_HASH_TABLE, 'm__Hashtable_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
                          return weights;

                      var hashtableEntries = hashtableTag.getChildNodeIterator();
                      if (this._invalid.iterator(hashtableEntries, 'm__Hashtable_tag_does_not_have_children_check_with_ml_platform'))
                          return weights;

                      var entryNode, entry = {};
                      while (hashtableEntries.hasNext() && (entryNode = hashtableEntries.next()) != null) {
                          if (entryNode.getNodeName() == this._TEXTNODE)
                              continue;

                          var entryChildren = entryNode.getChildNodeIterator(),
                              entryChild;
                          while (!gs.nil(entryChildren) && entryChildren.hasNext() && (entryChild = entryChildren.next()) != null) {
                              if (entryChild.getNodeName() == this._TEXTNODE)
                                  continue;

                              entry[entryChild.getNodeName()] = entryChild.getTextContent();
                          }

                          if (this._invalid.condition(Object.keys(entry).length != 2, 'm__Hashtable_tag_does_not_have_2_children_check_with_ml_platform'))
                              return weights;

                          columnMap[entry[this._XML_TAG_STRING]] = columnMap["label_index_" + entry[this._XML_TAG_INT]];
                      }

                  } else
                      childData[wekaAttributeChild.getNodeName()] = wekaAttributeChild.getTextContent();

              }

              if (!childData[this._XML_TAG_ATTRIBUTE_INFO] && childData[this._XML_TAG_TYPE] == '0')
                  indexToFeatureNameMap[childData[this._XML_TAG_INDEX]] = columnMap[childData[this._XML_TAG_NAME]];
              else {
                  if (this._invalid.condition(!childData[this._XML_TAG_ATTRIBUTE_INFO], 'm__AttributeInfo_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
                      return weights;

                  indexToFeatureNameMap[childData[this._XML_TAG_INDEX]] = 'outputLabel';
              }
          }



          var model = weightsDoc.getFirstNode(xpath + '/m__Model/' + this._XML_TAG_MODEL_WIGHTS);
          if (this._invalid.node(model, 'w_tag_not_present_check_with_ml_platform_team_if_version_has_changed'))
              return weights;

          var weightsList = model.getChildNodeIterator();
          if (this._invalid.iterator(weightsList, 'w_tag_does_not_have_children_check_with_ml_platform_if_version_has_changed'))
              return weights;

          var weight, featurecount = 0,
              lastWeight;
          while (weightsList.hasNext() && (weight = weightsList.next()) != null) {
              if (weight.getNodeName() == this._TEXTNODE)
                  continue;

              var feature = indexToFeatureNameMap[featurecount++];
              if (!gs.nil(feature) && feature != 'outputLabel')
                  weights[feature] = weight.getTextContent();

              lastWeight = weight.getTextContent();
          }
          weights.feature_count = featurecount;


          var biasClassAndProbabilityTag = weightsDoc.getFirstNode('/' + root + '/trainerResult/' + this._XML_TAG_BIAS_CLASS_AND_PROBABILITY);
          if (this._invalid.node(biasClassAndProbabilityTag, 'biasClassAndProbabiity_not_present_check_with_ml_platform_team_if_version_has_changed'))
              return weights;

          var biasClassAndProbabilityTagChildren = biasClassAndProbabilityTag.getChildNodeIterator();
          if (this._invalid.iterator(biasClassAndProbabilityTagChildren, 'biasClassAndProbabiity_tag_does_not_have_children_check_with_ml_platform_if_version_has_changed'))
              return weights;

          var biasClassAndProbability;
          while (biasClassAndProbabilityTagChildren.hasNext() && (biasClassAndProbability = biasClassAndProbabilityTagChildren.next()) != null) {
              if (biasClassAndProbability.getNodeName() != this._TEXTNODE)
                  break;
          }

          if (this._invalid.condition(gs.nil(biasClassAndProbability) || biasClassAndProbability.getNodeName() != 'entry', 'biasClassAndProbabiity_tag_first_child_null_check_with_ml_platform_if_version_has_changed'))
              return weights;

          var biasClassAndProbabilityEntries = biasClassAndProbability.getChildNodeIterator();
          if (this._invalid.iterator(biasClassAndProbabilityEntries, 'biasClassAndProbabiity_tag_first_child_null_check_with_ml_platform_if_version_has_changed'))
              return weights;

          var biasClass;
          while (biasClassAndProbabilityEntries.hasNext() && (biasClass = biasClassAndProbabilityEntries.next()) != null) {
              if (biasClass.getNodeName() != this._TEXTNODE)
                  break;
          }
          var noMatchRecords = this._getRecordCount(this._NO_MATCH);
          var matchRecords = this._getRecordCount(this._MATCH);
          var biasClassLableFromData = matchRecords > noMatchRecords ? this._MATCH : this._NO_MATCH;

          if ("class0".equalsIgnoreCase(biasClass.getTextContent())) {
              //bias class is class0
              if (this._MATCH == biasClassLableFromData) {
                  //class0 = 1 from labels
                  if (this._MATCH == columnMap["class0"]) {
                      //weka class0 is 1 in ARFF format
                      //class0 = 1 from labels
                      weights["rev"] = "false";
                  } else if (this._NO_MATCH == columnMap["class0"]) {
                      //class = 0 from weka
                      weights["rev"] = "true";
                  } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                      return weights;
              } else if (this._NO_MATCH == biasClassLableFromData) {
                  //class0 = 0 from labels
                  if (this._MATCH == columnMap["class0"]) {
                      //weka class0 is 1 in ARFF format
                      //class0 = 0 from labels
                      weights["rev"] = "true";
                  } else if (this._NO_MATCH == columnMap["class0"]) {
                      //class = 0 from weka
                      weights["rev"] = "false";
                  } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                      return weights;
              } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                  return weights;
          } else if ("class1" == biasClass.getTextContent()) {
              //bias class is class1
              if (this._MATCH == biasClassLableFromData) {
                  //class1 = 1 from labels
                  if (this._MATCH == columnMap["class1"]) {
                      //class1 = 1 from weka
                      weights["rev"] = "false";
                  } else if (this._NO_MATCH == columnMap["class1"]) {
                      //class1=0 from weka
                      weights["rev"] = "true";
                  } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                      return weights;
              } else if (this._NO_MATCH == biasClassLableFromData) {
                  //class1 = 0 from labels
                  if (this._MATCH == columnMap["class1"]) {
                      //class1 = 1 from weka
                      weights["rev"] = "true";
                  } else if (this._NO_MATCH == columnMap["class1"]) {
                      //class1=0 from weka
                      weights["rev"] = "false";
                  } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                      return weights;
              } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
                  return weights;
          } else if (this._invalid.condition(true, 'There_cannot_be_more_than_2_classes'))
              return weights;

          weights[this._BIAS] = lastWeight;
          weights.status = "SUCCESS";
      } catch (ex) {
          this._invalid.condition(true, 'UNHANDLED EXCEPTION');
      }
      return weights;
  },

  _getRecordCount: function(label) {
      var gr = new GlideAggregate(this._CMDB_DYNAMIC_IRE_MATCH);
      gr.addQuery('expected_match', label);
      gr.addAggregate('COUNT');
      gr.query();
      var records = 0;
      if (gr.next()) {
          records = gr.getAggregate('COUNT');
      }
      return records;
  },


  /**
   * Helper method to fetch the modelXML from the
   * ml platform tables
   * @param the sysId of the solution.
   * @param the version of the solution.
   * @return XML string of the model.
   */
  _getArtifactStream: function(solutionSysId, id, mlSolutionVersion) {
      var model = new GlideRecord(this._ML_MODEL_ARTIFACT);
      model.addQuery(this._TABLE_REF_SOLUTION, solutionSysId);
      model.addQuery(this._MODEL_ID, id);

      if (!gs.nil(mlSolutionVersion))
          model.addQuery(this._TABLE_REF_SOLUTION + this._DOT + this._VERSION, mlSolutionVersion);
      else {
          model.addQuery(this._TABLE_REF_SOLUTION + this._DOT + this._ACTIVE, 'true');
          model.orderByDesc(this._TABLE_REF_SOLUTION + this._DOT + this._SYS_CREATED_ON);
      }

      model.query();
      if (!model.next())
          return null;

      var attachment = new GlideSysAttachment();
      var agr = attachment.getAttachments(this._ML_MODEL_ARTIFACT, model.getUniqueValue());
      if (!agr.next())
          return null;

      return sn_cmdb.DynamicIREScriptableAPI.getDecompressedAttachmentStream(agr.getUniqueValue());
  },

  type: 'CMDBDynamicIREMLInterface'
};

Sys ID

20137fa0c33220104ef3c31b7940ddc0

Offical Documentation

Official Docs: