Alex Conner
Alex Conner

Reputation: 260

Using AWS Lambda with Elastic Search, getting Undefined from the search client

I'm trying to learn Nodejs while simultaneously learning AWS platform.

I'm building a Lex application that uses a Lambda function with an AWS Elastic Search instance.

My search is basic and is finding what it needs to, the thing is when I test my handler it doesn't receive the data. When I log the results to the console, it seems like the search result object doesn't get passed back to the handler function until after the handler has already printed the results. Using some console logs I get this output:

Starting handler function
Starting search
{ dialogAction:
   { type: 'Close',
     fulfillmentState: 'Fulfilled',
     message: { contentType: 'PlainText', content: undefined  } } }
Top hit: [object Object]

The content item is undefined, but should instead be the Top Hit object that is returned from search.js. I can see the TopHit object is being found, but why is the index.handler function printing before the search response is returned?

My Lambda Handler function in index.js:

const search = require("./search.js");
exports.handler = (event, context, callback) => {

console.log("Starting handler function");

const questionReq = event.currentIntent.slots.question;
//console.log(questionReq);
// call Exported function from search js.Pass in string as question
const results = search.searchQuestion(questionReq);

const eventResponse = {
    "dialogAction": {
    "type": "Close",
    "fulfillmentState": "Fulfilled",
    "message": {
      "contentType": "PlainText",
      "content": results
    }
  }
};

callback(null, eventResponse);
};

My Elastic Search in search.js:

const client = require('./connection.js');

exports.searchQuestion = function(question)
{
    var topHit = "";
    console.log("Starting search");
    client.search({
      index: 'library',
      type: 'dsa',
      body: {
        query: {
          match: { "q": question }
        },
      }
  }).then(function (resp){
      topHit = resp.hits.hits[0];
      console.log("Top hit: " + topHit);
  }, function(err){
      console.trace(err.message);
  })
    return JSON.stringify(topHit);
}

Thanks in advance for any suggestions.

Upvotes: 0

Views: 2681

Answers (1)

NItin Vaja
NItin Vaja

Reputation: 177

Your searchQuestion function is async, it is returning a promise.

Your code should look something like this:

const search = require("./search.js");
exports.handler = (event, context, callback) => {
    console.log("Starting handler function");

    const questionReq = event.currentIntent.slots.question;
    //console.log(questionReq);
    // call Exported function from search js.Pass in string as question
    search.searchQuestion(questionReq)
        .then(result => {
            const eventResponse = {
                "dialogAction": {
                    "type": "Close",
                    "fulfillmentState": "Fulfilled",
                    "message": {
                        "contentType": "PlainText",
                        "content": results
                    }
                }
            };
          callback(null, eventResponse);
      });
};

Your Elastic Search in search.js:

const client = require('./connection.js');

exports.searchQuestion = function(question)
{
    return new Promise(function(resolve, reject) {
       var topHit = "";
       console.log("Starting search");
       client.search({
         index: 'library',
         type: 'dsa',
         body: {
           query: {
             match: { "q": question }
          },
        }
     }).then(function (resp){
         topHit = resp.hits.hits[0];
         return resolve(topHit);
     }, function(err){
         console.trace(err.message);
    });
  });
}

I hope this helps :).

Upvotes: 2

Related Questions