1

I have to integrate AWS Machine Learning service with Salesforce. I implemented JavaScript SDK

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/MachineLearning.html#predict-property

and it is working well.

But I have to implement API using batch apex and schedule the batch class.

http://docs.aws.amazon.com/machine-learning/latest/APIReference/API_Predict.html

I managed to implement this using apex but I get incorrect response and also same response for all the records (batch size is 1). Any ideas?

Batch Class -

global class AWSPredictionBatchSch implements Database.Batchable<sObject>, Database.AllowsCallouts {


global Database.QueryLocator start(Database.BatchableContext bc){ 
    String query = 'Select id, Name, ..... from Account';

    system.debug('--Query--' + query);

    return Database.getQueryLocator(query);
}

global void execute(Database.BatchableContext bc, List<Account> objects){
    system.debug('objects size: '+objects.size());
    processList(objects);
}

global void finish(Database.BatchableContext bc){

}

private void processList(List<Account> scope) {

    String AWSAccessKeyId = '******';
    String SecretAccessKey = '*****';        

    List<Account> updatePRCClients = new List<Account>();        

    system.debug('scope: '+scope );

    for(Account prc : scope ) {        

        String timestamp = DateTime.Now().formatGMT('yyyyMMdd\'T\'HHmmss\'Z\'');
        Date dt = DateTime.Now().dateGMT();
        String datestamp = '' + dt.year();

        if(dt.Month() <= 9)
            datestamp += '0' + dt.Month();
        else
            datestamp += dt.Month();

         if(dt.day() <= 9)
             datestamp += '0' + dt.day();
        else
            datestamp += dt.day();

        String Credential = AWSAccessKeyId + '/' + datestamp + '/us-east-1/machinelearning/aws4_request' ;

        String reqBody = generateRequestBody(prc);        

        system.debug('reqBody:: '+reqBody);

        Blob requestPayload = Crypto.generateDigest('SHA-256', Blob.valueOf(reqBody));
        String HashedPayload = EncodingUtil.convertToHex(requestPayload).toLowerCase();

        String CanonicalForm = 'POST\n/\n\ncontent-type:application/x-amz-json-1.1\n';
        CanonicalForm += 'host:realtime.machinelearning.us-east-1.amazonaws.com\nx-amz-date:'+timestamp+'\n';
        CanonicalForm += 'x-amz-target:AmazonML_20141212.Predict\n\ncontent-type;host;x-amz-date;x-amz-target\n';
        CanonicalForm += HashedPayload;
        system.debug('CanonicalForm: '+CanonicalForm);

        Blob targetBlob = Blob.valueOf(CanonicalForm);
        Blob CanonicalRequest = Crypto.generateDigest('SHA-256', targetBlob);
        String HashedCanonicalRequest = EncodingUtil.convertToHex(CanonicalRequest);

        String StringToSign = 'AWS4-HMAC-SHA256\n'+timestamp+'\n'+datestamp+'/us-east-1/machinelearning/aws4_request\n';
        StringToSign += HashedCanonicalRequest;
        system.debug('StringToSign:: '+StringToSign);

        Blob bSignatureKey = getSignatureKey(SecretAccessKey, datestamp, 'us-east-1', 'machinelearning');
        String Signature = EncodingUtil.convertToHex(crypto.generateMac('HmacSHA256', Blob.valueOf(StringToSign), bSignatureKey));

        String authorizationHeader = 'AWS4-HMAC-SHA256 Credential=' + Credential + ', SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=' + Signature;

        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://realtime.machinelearning.us-east-1.amazonaws.com');
        req.setMethod('POST');
        req.setHeader('authorization',authorizationHeader);
        req.setHeader('content-type','application/x-amz-json-1.1');
        req.setHeader('x-amz-date',timestamp);
        req.setHeader('x-amz-target','AmazonML_20141212.Predict');
        req.setHeader('connection', 'Keep-Alive');
        req.setBody(reqBody);

        Http http = new Http();
        HTTPResponse res = http.send(req);
        System.debug('response:: '+ res.getBody());

        if(res.getStatus() == 'OK') {

            Account PRCClient = new Account();
            PRCClient.id = prc.id;
            PRCClient.AWS_Prediction__c = getPredictedLabel(res.getBody());
            if(PRCClient.AWS_Prediction__c == 'No')
                PRCClient.AWS_Prediction_Score__c = getPredictedScore('0', res.getBody());
            else
                PRCClient.AWS_Prediction_Score__c = getPredictedScore('1', res.getBody());
            updatePRCClients.add(PRCClient);
            system.debug('PRCClient: '+PRCClient);
        }
    } // EOF
    system.debug('updatePRCClients: '+updatePRCClients);
    if(updatePRCClients.size() > 0)
        update updatePRCClients;
}

private Blob getSignatureKey(String key, String dateStamp, String regionName, String serviceName)  {
    Blob kSecret = Blob.valueOf('AWS4' + key);
    Blob kDate    = crypto.generateMac('HmacSHA256', Blob.valueOf(dateStamp), kSecret);
    Blob kRegion  = crypto.generateMac('HmacSHA256', Blob.valueOf(regionName), kDate);
    Blob kService = crypto.generateMac('HmacSHA256', Blob.valueOf(serviceName), kRegion);
    Blob kSigning = crypto.generateMac('HmacSHA256', Blob.valueOf('aws4_request'), kService);
    return kSigning;
}

private String generateRequestBody(Account prc) {


    String reqBody = '';
    reqBody = '{"MLModelId": "abcd","PredictEndpoint": "https://realtime.machinelearning.us-east-1.amazonaws.com",';
    reqBody += '"Record":{';
    reqBody += '"Client_ID" : "' + prc.Name + '",';
    reqBody += '"Account" : "' + String.escapeSingleQuotes(prc.PRC__r.Name) + '",';
    ...
    ...
    ...
    reqBody += '}}';

    return reqBody;    
}
}

I get different responses for same record. Response received from SDK is correct.

Response from http request-

"{"Prediction":{"details":{"Algorithm":"SGD","PredictiveModelType":"BINARY"},"predictedLabel":"0","predictedScores":{"0":0.03352721035480499}}}"

Response from SDK -

"{"Prediction":{"details":{"Algorithm":"SGD","PredictiveModelType":"BINARY"},"predictedLabel":"1","predictedScores":{"1":0.9637616872787476}}}"

2
  • welcome to the community. please add your batch class code as well by editing this question.
    – Himanshu
    Jan 13 '16 at 20:57
  • Can you post your apex code and response provided by the api? Jan 13 '16 at 23:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.