Память BigQuery UDF превысила ошибку в нескольких строках, но отлично работает в одной строке

Я пишу UDF для обработки данных Google Analytics и получаю сообщение об ошибке "UDF out of memory" при попытке обработать несколько строк. Я загрузил необработанные данные, нашел самую большую запись и попытался выполнить свой UDF-запрос по этому вопросу, но с успехом. Некоторые строки имеют до 500 вложенных попаданий, и размер записи попаданий (безусловно, самый большой компонент каждой строки необработанных данных GA), похоже, влияет на количество строк, которые я могу обработать до получения ошибки,

Например, запрос

select 
    user.ga_user_id, 
    ga_session_id, 
        ...
from 
    temp_ga_processing(
        select 
            fullVisitorId, 
            visitNumber, 
                   ...            
        from [79689075.ga_sessions_20160201] limit 100)

возвращает ошибку, но

from [79689075.ga_sessions_20160201] where totals.hits = 500 limit 1) 

не.

У меня сложилось впечатление, что какие-то ограничения памяти были на ряд? Я пробовал несколько методов, таких как установка row = null; до emit(return_dict); (где return_dict - обработанные данные), но безрезультатно.

Сам UDF не делает ничего особенного; Я вставил бы это здесь, но это ~45 кБ в длину. По сути, он делает кучу вещей в соответствии с:

function temp_ga_processing(row, emit) {
  topic_id = -1;
  hit_numbers = [];
  first_page_load_hits = [];
  return_dict = {};
  return_dict["user"] = {};
  return_dict["user"]["ga_user_id"] = row.fullVisitorId;
  return_dict["ga_session_id"] = row.fullVisitorId.concat("-".concat(row.visitNumber));
  for(i=0;i<row.hits.length;i++) {
    hit_dict = {};
    hit_dict["page"] = {};
    hit_dict["time"] = row.hits[i].time;
    hit_dict["type"] = row.hits[i].type;
    hit_dict["page"]["engaged_10s"] = false;
    hit_dict["page"]["engaged_30s"] = false;
    hit_dict["page"]["engaged_60s"] = false;

    add_hit = true;
    for(j=0;j<row.hits[i].customMetrics.length;j++) {
      if(row.hits[i].customDimensions[j] != null) {
        if(row.hits[i].customMetrics[j]["index"] == 3) {
          metrics = {"video_play_time": row.hits[i].customMetrics[j]["value"]};
          hit_dict["metrics"] = metrics;
          metrics = null;
          row.hits[i].customDimensions[j] = null;
        }
      }
    }

    hit_dict["topic"] = {};
    hit_dict["doctor"] = {};
    hit_dict["doctor_location"] = {};
    hit_dict["content"] = {};

    if(row.hits[i].customDimensions != null) {
      for(j=0;j<row.hits[i].customDimensions.length;j++) {
        if(row.hits[i].customDimensions[j] != null) {
          if(row.hits[i].customDimensions[j]["index"] == 1) {
            hit_dict["topic"] = {"name": row.hits[i].customDimensions[j]["value"]};
            row.hits[i].customDimensions[j] = null;
            continue;
          }
          if(row.hits[i].customDimensions[j]["index"] == 3) {
            if(row.hits[i].customDimensions[j]["value"].search("doctor") > -1) {
              return_dict["logged_in_as_doctor"] = true;
            }
          }
          // and so on...
        }
      }
    }
    if(row.hits[i]["eventInfo"]["eventCategory"] == "page load time" && row.hits[i]["eventInfo"]["eventLabel"].search("OUTLIER") == -1) {
      elre = /(?:onLoad|pl|page):(\d+)/.exec(row.hits[i]["eventInfo"]["eventLabel"]);
      if(elre != null) {
        if(parseInt(elre[0].split(":")[1]) <= 60000) {
          first_page_load_hits.push(parseFloat(row.hits[i].hitNumber));
          if(hit_dict["page"]["page_load"] == null) {
            hit_dict["page"]["page_load"] = {};
          }
          hit_dict["page"]["page_load"]["sample"] = 1;
          page_load_time_re = /(?:onLoad|pl|page):(\d+)/.exec(row.hits[i]["eventInfo"]["eventLabel"]);
          if(page_load_time_re != null) {
            hit_dict["page"]["page_load"]["page_load_time"] = parseFloat(page_load_time_re[0].split(':')[1])/1000;
          }
        }
        // and so on...  
      }
    }    
  row = null;
  emit return_dict;
}

Идентификатор задания является реальным:bquijob_4c30bd3d_152fbfcd7fd

3 ответа

Обновление Авг 2016: Мы выпустили обновление, которое позволит работнику JavaScript использовать вдвое больше оперативной памяти. Мы продолжим отслеживать задания, потерпевшие неудачу с помощью JS OOM, чтобы выяснить, не нужно ли еще больше; А пока, пожалуйста, сообщите нам, если у вас не получится работать с OOM. Спасибо!

Обновление: эта проблема была связана с ограничениями, которые у нас были на размер кода UDF. Похоже, что проход V8 для оптимизации + перекомпиляции кода UDF генерирует сегмент данных, который был больше наших пределов, но это происходило только тогда, когда UDF пробегает "достаточное" количество строк. На этой неделе я встречаюсь с командой V8, чтобы углубиться в детали.

@Grayson - мне удалось успешно выполнить вашу работу за всем столом 20160201; выполнение запроса занимает 1-2 минуты. Не могли бы вы убедиться, что это работает на вашей стороне?


Мы получили несколько сообщений о похожих проблемах, которые, похоже, связаны с обработкой # строк. Я извиняюсь за беспокойство; Я проведу некоторое профилирование в нашей среде выполнения JavaScript, чтобы попытаться выяснить, происходит ли утечка памяти. Оставайтесь с нами для анализа.

В то же время, если вы сможете выделить какие-либо конкретные строки, которые вызывают ошибку, это также будет очень полезно.

UDF не будет работать ни с чем, кроме очень маленьких наборов данных, если у него много уровней if/then, таких как:
если () {
.... если() {
.........если () {
так далее

Мы должны были отследить и удалить самое глубокое утверждение if/then.

Но этого недостаточно. Кроме того, когда вы передаете данные в UDF, запустите "GROUP EACH BY" для всех переменных. Это заставит BQ отправить вывод нескольким "рабочим". Иначе это тоже не получится.

Я потратил 3 дня своей жизни на эту досадную ошибку. Argh.

Мне нравится концепция парсинга моих логов в BigQuery, но у меня та же проблема, я получаю

Ошибка: ресурсы превышены во время выполнения запроса.

Идентификатор задания выглядит так:bquijob_260be029_153dd96cfdb, если это вообще помогает.

Я написал очень простой парсер, который выполняет простое сопоставление и возвращает строки. Прекрасно работает с набором данных из 10К строк, но у меня не хватает ресурсов, когда я пытаюсь запустить файл журнала из 3М строк.

Любые предложения для обхода?

Вот код JavaScript.

function parseLogRow(row, emit) {

  r =  (row.logrow ? row.logrow : "") + (typeof row.l2 !== "undefined" ? " " + row.l2 : "") + (row.l3 ? " " + row.l3 : "")
  ts = null
  category = null
  user = null
  message = null
  db = null
  found = false
  if (r) {
      m = r.match(/^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d (\+|\-)\d\d\d\d) \[([^|]*)\|([^|]*)\|([^\]]*)\] :: (.*)/ )
      if( m){
        ts = new Date(m[1])/1000
        category = m[3] || null
        user = m[4] || null
        db = m[5] || null
        message = m[6] || null
        found = true
      }
      else {
        message = r
        found = false
      }
   }

  emit({
    ts:  ts,
    category: category,
    user: user,
    db: db,
    message: message,
    found: found
    });
}

bigquery.defineFunction(
  'parseLogRow',                           // Name of the function exported to SQL
  ['logrow',"l2","l3"],                    // Names of input columns
  [
    {'name': 'ts', 'type': 'timestamp'},  // Output schema
    {'name': 'category', 'type': 'string'},
    {'name': 'user', 'type': 'string'},
    {'name': 'db', 'type': 'string'},
    {'name': 'message', 'type': 'string'},
    {'name': 'found', 'type': 'boolean'},
  ],
  parseLogRow                          // Reference to JavaScript UDF
);
Другие вопросы по тегам