netsuite
Поиски с большим количеством результатов
Поиск…
Вступление
В приложении SuitesScript 2.0 предусмотрены 4 метода обработки результатов поиска.
Они имеют различный синтаксис, ограничения и управление и подходят для разных ситуаций. Мы сосредоточимся здесь о том , как получить доступ ко всем результатам поиска, используя каждый из этих методов.
Использование метода Search.ResultSet.each
Это самый короткий, самый простой и наиболее часто используемый метод. К сожалению, он имеет одно основное ограничение - не может использоваться для поиска с более чем 4000 результатами (строками).
// Assume that 'N/search' module is included as 'search'
var s = search.create({
type : search.Type.TRANSACTION,
columns : ['entity','amount'],
filters : [ ['mainline', 'is', 'T'],
'and', ['type', 'is', 'CustInvc'],
'and', ['status', 'is', 'open']
]
});
var resultSet = s.run();
// you can use "each" method on searches with up to 4000 results
resultSet.each( function(result) {
// you have the result row. use it like this....
var transId = result.id;
var entityId = result.getValue('entity');
var entityName = result.getText('entity');
var amount = result.getValue('amount');
// don't forget to return true, in order to continue the loop
return true;
});
Использование метода ResultSet.getRange
Чтобы использовать getRange для обработки большого количества результатов, нам нужно будет рассмотреть следующее:
- getRange имеет 2 параметра: начало и конец . Всегда положительный, всегда (начало <конец)
- start - это инклюзивный индекс первого результата для возврата
- end - это эксклюзивный индекс последнего результата для возврата
- Если доступно меньше результатов, чем запрошено, тогда массив будет содержать меньше, чем начальные записи. Например, если есть только 25 результатов поиска, getRange (20, 30) вернет массив из 5 объектов search.Result.
- Хотя приведенное выше предложение поддержки не говорит об этом напрямую, начало и конец могут быть вне диапазона доступных результатов. В том же примере - если есть только 25 результатов поиска, getRange (100, 200) вернет пустой массив []
- Максимум 1000 строк за раз. (конец - старт) <= 1000
// Assume that 'N/search' module is included as 'search'
// this search will return a lot of results (not having any filters)
var s = search.create({
type: search.Type.TRANSACTION,
columns : ['entity','amount'],
filters: []
});
var resultSet = s.run();
// now take the first portion of data.
var currentRange = resultSet.getRange({
start : 0,
end : 1000
});
var i = 0; // iterator for all search results
var j = 0; // iterator for current result range 0..999
while ( j < currentRange.length ) {
// take the result row
var result = currentRange[j];
// and use it like this....
var transId = result.id;
var entityId = result.getValue('entity');
var entityName = result.getText('entity');
var amount = result.getValue('amount');
// finally:
i++; j++;
if( j==1000 ) { // check if it reaches 1000
j=0; // reset j an reload the next portion
currentRange = resultSet.getRange({
start : i,
end : i+1000
});
}
}
Позволяет рассчитать управление. У нас есть 1 + счет / 1000 вызовов getRange, каждый из которых составляет 10 единиц, поэтому:
G = (1 + счет / 1000) * 10
Пример: 9500 строк будут принимать 100 единиц
Использование метода Search.PagedData.fetch
PagedData - это объект, возвращаемый методом Search.runPaged (options). Он работает точно так же, как и пользовательский интерфейс. Объект PagedData содержит 2 важных свойства, которые вы можете увидеть в правой части заголовка результатов на странице результатов поиска в пользовательском интерфейсе Netsuite:
- count (общее количество результатов)
- pageRanges (список страниц, доступных в пользовательском интерфейсе как селектор со списком)
Параметр options.pageSize снова ограничен 1000 строками результата.
Метод PagedData.fetch используется для извлечения нужной части результата (индексируется параметром pageIndex). С немного больше кода вы получаете ту же удобную функцию обратного вызова, что и Search.ResultSet.each, без ограничения на 4000 строк.
// Assume that 'N/search' module is included as 'search'
// this search will return a lot of results (not having any filters)
var s = search.create({
type: search.Type.TRANSACTION,
columns : ['entity','amount'],
filters : []
});
var pagedData = s.runPaged({pageSize : 1000});
// iterate the pages
for( var i=0; i < pagedData.pageRanges.length; i++ ) {
// fetch the current page data
var currentPage = pagedData.fetch(i);
// and forEach() thru all results
currentPage.data.forEach( function(result) {
// you have the result row. use it like this....
var transId = result.id;
var entityId = result.getValue('entity');
var entityName = result.getText('entity');
var amount = result.getValue('amount');
});
}
Позволяет рассчитать управление. У нас есть 5 единиц для вызовов runPaged () и 1 + count / 1000 pagedData.fetch, каждый из которых занимает 5 единиц, поэтому:
G = 5 + ceil (количество / 1000) * 5
Пример: 9500 строк занимают 55 единиц. Примерно половина единиц управления getRange.
Использование специального сценария Map / Reduce
Для действительно огромных результатов поиска вы можете использовать выделенный сценарий Map / Reduce. Это гораздо более неудобно, но иногда неизбежно. И иногда это может быть очень удобно.
Хитрость здесь заключается в том, что на этапе ввода входных данных вы можете предоставить NS-движку не фактические данные (т. Е. Результат скрипта), а просто определение поиска. NS выполнит поиск для вас без учета единиц управления. Затем каждая строка результата будет передана на этап Map.
Конечно, существует ограничение: общий сохраненный размер данных для сценария map / reduce не может превышать 50 МБ. В результате поиска каждый ключ и сериализованный размер каждого значения подсчитываются по отношению к общему размеру. «Сериализованный» означает, что строка результата поиска преобразуется в строку с помощью JSON.stringify. Таким образом, размер значения пропорционален количеству столбцов результатов поиска в наборе результатов. Если вы столкнулись с проблемами с ошибкой STORAGE_SIZE_EXCEEDED, подумайте об уменьшении столбцов, объединении с формулами, группировании результата или даже разбиении поиска на несколько подпоследований, которые могут быть выполнены на этапах Map или Reduce.
/**
* @NApiVersion 2.0
* @NScriptType MapReduceScript
*/
define(['N/search'], function(search) {
function getInputData()
{
return search.create({
type: search.Type.TRANSACTION,
columns : ['entity','amount'],
filters : []
});
}
function map(context)
{
var searchResult = JSON.parse(context.value);
// you have the result row. use it like this....
var transId = searchResult.id;
var entityId = searchResult.values.entity.value;
var entityName = searchResult.values.entity.text;
var amount = searchResult.values.amount.value;
// if you want to pass some part of the search result to the next stage
// write it to context:
context.write(entityId, transId);
}
function reduce(context)
{
// your code here ...
}
function summarize(summary)
{
// your code here ...
}
return {
getInputData: getInputData,
map: map,
reduce: reduce,
summarize: summarize
};
});
Конечно, пример здесь упрощен, без обработки ошибок и дается просто для сравнения с другими. Дополнительные примеры доступны в примерах Map / Reduce Script Type в справочном центре NS