Exploring MapReduce Script Context Objects in NetSuite
In this blog, I won’t dive into the script functions of a MapReduce script. Instead, I'll explain the context objects within each stage of the script, helping you understand their significance for better script performance and reliability in NetSuite. Writing a script isn’t just about making it work; it’s about making it efficient, scalable, and robust.
Knowing when and how to use each context object lets you
optimize usage, handle errors gracefully, and ensure consistent execution even
if interruptions occur. This approach will help you better leverage the
properties and methods available at each stage - getInputData, map, reduce, and summarize—for
more effective scripting in NetSuite.
1. getInputData
Context Object: (inputContext):
The `inputContext` object is utilized in the `getInputData(inputContext)` function, helping to load data for further stages. Its properties allow the script to check if it's being restarted and reference specific input data sources.
Properties:
- inputContext.isRestarted:
- Indicates if the current call to `getInputData` is due to an application server restart. This flag enables you to handle re-executions gracefully, ensuring no data is lost.
Example:
function getInputData(context) {
if (context.isRestarted) {
log.debug('GET_INPUT isRestarted', 'YES');
} else {
log.debug('GET_INPUT isRestarted', 'NO');
}
return search.load({ id: 'customsearch35' });
}
- inputContext.ObjectRef:
- Contains details about the input data type and its identifier, such as a SuiteQL query, file path, or saved search ID.
Example:
function getInputData(context) {
//suiteQL query
rerturn {
type: 'suiteql',
query: 'SELECT id, email FROM Employee WHERE currency = ?',
params: [currency]
}
//SEARCH
return {
type: search,
id: 26,
}
}
2. mapContext Object:
The `mapContext` object is used within the `map(mapContext)` function. It represents each key-value pair and offers various properties and methods for handling and writing data to pass along to the reduce stage.
Properties:
- mapContext.isRestarted:
- Indicates if `map(mapContext)` has restarted due to an interruption, which can help manage duplicate processing.
Example:
function map(context) {
if (context.isRestarted) {
// Assess previously completed processing steps
} else {
// Process key-value pair normally
}
}
- mapContext.executionNo:
- Tracks the number of times the `map` function has been called for the current key-value pair, providing control over re-executions.
Example:
function map(context) {
if (context.executionNo === 1) {
// Full processing
} else if (context.executionNo === 2) {
// Handle partial completion
}
}
- mapContext.errors:
- A collection of serialized errors from previous attempts, useful for debugging by logging each error entry.
Example:
function map(context) {
context.errors.iterator().each((key, error, executionNo) => {
var errorObject = JSON.parse(error);
log.error({
title: 'Map error for key ' + key,
details: errorObject.name + ': ' + errorObject.message
});
return true;
});
}
- mapContext.key:
- The current key for processing in the map stage, which can vary depending on the input data type.
Example:
function map(context) {
context.write({
key: context.value[i],
value: 1
});
}
- mapContext.value:
- The current value associated with `mapContext.key`. This is usually a JSON string derived from a search result or another data source.
Example:
function map(context) {
var searchResult = JSON.parse(context.value);
}
- mapContext.write(options):
- Saves key-value pairs for processing in the reduce stage, essential for moving data between stages.
Example:
function map(context) {
for (var i = 0; context.value && i < context.value.length; i++) {
if (context.value[i] !== ' ' && !PUNCTUATION_REGEXP.test(context.value[i])) {
context.write({
key: context.value[i],
value: 1
});
}
}
}
3. reduceContext Object :
The `reduceContext` object is central in the
`reduce(reduceContext)` function, which consolidates values based on keys
provided by `mapContext.write(options)`.
Properties:
- reduceContext.isRestarted:
- Detects whether `reduce(reduceContext)` was restarted for a specific key, allowing duplication checks.
Example:
function reduce(context) {
if (context.isRestarted) {
// Check prior progress
} else {
// Proceed with full processing
}
}
- reduceContext.executionNo:
- Shows the number of attempts for the `reduce` function with the current key, useful for retry logic.
Example:
function reduce(context) {
if (context.executionNo === 1) {
// Process fully
} else if (context.executionNo === 2) {
// Handle intermediate progress
}
}
- reduceContext.errors:
- Logs errors encountered in previous attempts, allowing you to understand and resolve repeated issues.
Example:
function reduce(context) {
context.errors.iterator().each((key, error, executionNo) => {
var errorObject = JSON.parse(error);
log.error({
title: 'Reduce error for key ' + key,
details: errorObject.name + ': ' + errorObject.message
});
return true;
});
}
- reduceContext.key:
- Refers to each key passed from the `mapContext` stage.
Example:
function reduce(context) {
context.write({
key: context.key,
value: context.values.length
});
}
- reduceContext.values:
- Holds an array of all values associated with a unique key, generally formatted in lexicographical order.
Example:
function reduce(context) {
context.write({
key: context.key,
value: context.values.length
});
}
- reduceContext.write(options):
- Passes key-value pairs to the summarize stage for further processing.
Example:
function reduce(context) {
context.write({
key: context.key,
value: context.values.length
});
}
4. summaryContext Object:
Finally, the `summaryContext` object in the
`summarize(summaryContext)` function provides performance metrics and error
logs for all stages of the MapReduce script.
Properties:
- summaryContext.isRestarted:
- Shows if the summarize function is being rerun due to a restart.
Example:
function summarize(summary) {
if (summary.isRestarted) {
log.debug('SUMMARY isRestarted', 'YES');
} else {
log.debug('SUMMARY isRestarted', 'NO');
}
}
- summaryContext.concurrency:
- Indicates the concurrency level used in parallel processing for the script.
Example:
function summarize(summary) {
log.audit('Concurrency Number', summary.concurrency);
}
- summaryContext.dateCreated:
- The timestamp of when the script started.
Example:
function summarize(summary) {
log.audit('Creation Date', summary.dateCreated);
}
- summaryContext.seconds:
- Total seconds elapsed during the script's execution.
Example:
function summarize(summary) {
log.audit('Total seconds elapsed', summary.seconds);
}
- summaryContext.usage:
- Tracks the total usage units consumed by the script.
Example:
function summarize(summary) {
log.audit('Usage Consumed', summary.usage);
}
- summaryContext.yields:
- Shows the number of times the script yielded to other processes.
Example:
function summarize(summary) {
log.audit('Number of Yields', summary.yields);
}
- summaryContext.output:
- Provides key-value pairs created in the reduce stage.
Example:
function summarize(summary) {
var totalRecordsUpdated = 0;
summary.output.iterator().each((key, value) => {
log.audit({
title: 'Summary Output Iterator',
details: 'key: ' + key + ' / value: ' + value
});
totalRecordsUpdated++;
return true;
});
log.debug('Total records updated', totalRecordsUpdated);
}
- inputSummary
- dateCreated
- seconds
- usage
- error
- mapSummary
- concurrency
- dateCreated
- keys
- seconds
- usage
- yields
- errors
- reduceSummary
- concurrency
- dateCreated
- keys
- seconds
- usage
- yields
- errors
For additional details on summarize properties not covered here, refer to the NetSuite documentation.
This overview of each context object’s properties and
example usage gives you a thorough understanding of how to navigate and utilize
the data at each stage of a MapReduce script in NetSuite.
Comments
Post a Comment