Пользовательская функция BigQuery, сокращающая все строки

У меня определен следующий UDF (обратите внимание, что в моей таблице есть объект «Id» и «Чтение» с подполем «RawHex»):

// UDF definition
function hexdecode(row, emit) {
  emit({
    Id: row.Id,
    converted: decodeHelper(row.Reading.Raw)
  });
}

// Helper function with error handling
function decodeHelper(s) {
  try {
    return parseInt(s, 16);
  } catch (ex) {
    return s;
  }
}

// UDF registration
bigquery.defineFunction(
  'hexdecode',  // Name used to call the function from SQL

  ['Id', 'Reading.Raw'],  // Input column names

  // JSON representation of the output schema
  [{name: 'Id', type: 'STRING'},
   {name: 'converted', type: 'INTEGER'}],

  hexdecode  // The function reference
);

и мой запрос:

select Id, converted from 
hexdecode(
select r.Id, r.Reading.Raw from Example.TagRaw2 r
)

Генерируется путем загрузки следующего JSON в таблицу Example.TagRaw2

{"Id":"ABC","Reading":{"Raw":"0004"}}
{"Id":"CDE","Reading":{"Raw":"000b"}}

Я ожидал, что это преобразует мой столбец из Hex в Integer, но вместо этого if возвращает одну запись, которая почти не имеет смысла.

Любая идея, что я делаю неправильно?

РЕДАКТИРОВАТЬ: я добавил пример JSON для загрузки, чтобы попытаться воспроизвести проблему... но теперь он работает. Я обновлю снова, если смогу понять, что изначально было не так, но UDF, приведенный выше, похоже, делает именно то, что я хочу.


person GeorgeWilson    schedule 10.11.2015    source источник
comment
Почему вы выделяете «TagId» и определяете имя схемы как «Id»?   -  person Pentium10    schedule 10.11.2015
comment
Не возражаете ли вы включить пример ввода / вывода?   -  person Patrice    schedule 10.11.2015
comment
немного сложно, так как я не уверен, что я могу выложить на всеобщее обозрение - я попытаюсь воссоздать проблему с синтетическим набором.   -  person GeorgeWilson    schedule 10.11.2015
comment
пинг, когда вы это сделаете, пожалуйста!   -  person Felipe Hoffa    schedule 11.11.2015
comment
@FelipeHoffa Я добавил JSON, который вы можете загрузить, чтобы получить макет моей таблицы ... к сожалению, теперь запрос работает нормально ...   -  person GeorgeWilson    schedule 11.11.2015
comment
Если у вас есть идентификатор задания из вашей истории запросов для одного из неудачных заданий, мы можем изучить его.   -  person thomaspark    schedule 12.11.2015
comment
Спасибо, Томас, позвольте мне изучить это позже сегодня и вернуться к вам. Был отслежен другой работой и решил просто сделать это преобразование локально. Хотя хорошо, что это происходит.   -  person GeorgeWilson    schedule 12.11.2015
comment
Я думаю, что вы на правильном пути ниже, но я не совсем понял. Вот идентификатор задания, если вы хотите взглянуть: valued-vault-111213:job_d7yoKziSgyeqDUc4gG_SgXCW5jg   -  person GeorgeWilson    schedule 12.11.2015


Ответы (1)


Вопрос: ваш объект Reading случайно не является повторяющимся столбцом?

Если это так, вам нужно сделать что-то вроде этого:

function hexdecode(r, emit) {
  for (var i = 0; i < r.reading.length; ++i) {
    emit({ tag: r.Id, num: parseInt(r.reading[i].Raw, 16) });
  }
}

bigquery.defineFunction(
  'hexdecode',
  ['Id', 'reading.Raw'],
  [{name: 'tag', type: 'string'},
   {name: 'num', type: 'integer'}],
  hexdecode
);

Если вы попытаетесь получить доступ к r.reading.Raw, это будет попытка доступа к свойству Raw массива JavaScript. Это совершенно допустимый JavaScript, но это определенно не то, что вам нужно, поскольку значение не определено (null).

Один удобный прием — распечатать строку JSON входной записи, чтобы увидеть, что UDF видит в качестве входных данных:

bigquery.defineFunction(
  'jsonifyObj',
  ['Id', 'reading.Raw'],
  [{name: 'obj', type: 'string'}],
  function(r, emit) { emit({obj: JSON.stringify(r)}); }
);

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

[{"Id":"ABC","Reading":[{"Raw":"0004"}, {"Raw": "00ff"}]},
 {"Id":"CDE","Reading":[{"Raw":"000b"}, {"Raw": "0012"}]}]

-------- Обновление 2015-11-17 --------

В вашем коде есть несколько проблем, прокомментированных ПРИМЕЧАНИЕ ниже:

function hexdecode(row, emit) {
 for (var i = 0; i < row.reading.length; ++i) {
   // NOTE: tag and row.Id are wrong, this must be TagId and row.TagId based on your input and output specifications
   emit({ tag: row.Id,
          times: row.reading[i].Timestamp,
          // NOTE: You're making a recursive call here!  You should be calling decodeHelper() not hexdecode().
          convert: hexdecode(row.reading[i].RawCO) });
  }
}


// Helper function with error handling
function decodeHelper(s) {
  try {
    return parseInt(s, 16);
  } catch (ex) {
    return s;
  }
}

// UDF registration
bigquery.defineFunction(
  'hexdecode',  // Name used to call the function from SQL

  ['TagId', 'reading.Timestamp', 'reading.RawCO'],  // Input column names

  // JSON representation of the output schema
  [{name: 'TagId', type: 'STRING'},
   {name: 'times', type: 'INTEGER'},
   {name: 'convert', type: 'INTEGER'}],

  hexdecode  // The function reference
);

Ваш вложенный выбор возвращает 0 строк, поэтому я обновил следующий SQL:

select 
  TagID, times, convert 
from  hexdecode(
select r.TagId, r.Reading.Timestamp, r.Reading.RawCO from [table.Readings] r where r.Reading.RawCO is not NULL and r.Reading.PPM is
 not NULL
 and r.TagId = 'Tag_00000000' 
 )

А вот исправленный код:

function hexdecode(row, emit) {
  for (var i = 0; i < row.reading.length; ++i) {
    emit({TagId: row.TagId, times: row.reading[i].Timestamp, convert: decodeHelper(row.reading[i].RawCO)});
  }
}

// Helper function with error handling
function decodeHelper(s) {
  try {
    return parseInt(s, 16);
  } catch (ex) {
    return s;
  }
}

// UDF registration
bigquery.defineFunction(
  'hexdecode',  // Name used to call the function from SQL

  ['TagId', 'reading.Timestamp', 'reading.RawCO'],  // Input column names

  // JSON representation of the output schema
  [{name: 'TagId', type: 'STRING'},
   {name: 'times', type: 'INTEGER'},
   {name: 'convert', type: 'INTEGER'}],

  hexdecode  // The function reference
);
person thomaspark    schedule 11.11.2015
comment
Потрясающе.. Я думаю, это оно. Я попробую это и вернусь к вам позже. - person GeorgeWilson; 12.11.2015
comment
Хм, у меня это не совсем работает - длина r.reading не определена. Как именно вы распечатываете json? - person GeorgeWilson; 12.11.2015
comment
Итак, если вы использовали код для jsonifyObj, который я вставил выше, соответствующий выбор будет SELECT obj FROM jsonifyObj(select r.Id, r.Reading.Raw from Example.TagRaw2 r) - person thomaspark; 12.11.2015
comment
Извините, не могу получить доступ к этому вне работы - я свяжусь с вами как можно скорее - person GeorgeWilson; 14.11.2015
comment
Вы были правы насчет формата ввода, но у меня все еще проблемы. По-видимому, поле «длина» не определено. Вот идентификатор задания: valued-vault-111213:job_-cWTofri5UVAkxNgSdnNzFSCHso - person GeorgeWilson; 16.11.2015
comment
Похоже, что ваш запрос ссылается на r.Reading.Timestamp и r.Reading.RawCO, но JS ссылается на r.reading. Работает ли это, если вы читаете в верхнем регистре в своем JS? Подсказка находится в сообщении об ошибке: Cannot read property 'length' of undefined - не определена не длина, а объект, из которого осуществляется доступ, r.reading - person thomaspark; 17.11.2015
comment
Нет, если я переключаюсь на r.reading, то он говорит мне, что «ожидал r.reading, но получил r.Reading.RawCo». - person GeorgeWilson; 17.11.2015
comment
Ах, я не должен был говорить, не проверив твою работу. Вы обращаетесь к неопределенному свойству, но не из-за несоответствия имени поля. Вы случайно делаете рекурсивный вызов обработчику UDF. Это можно было бы уловить с помощью инструмента тестирования UDF. Я обновил свой ответ выше с полной информацией. - person thomaspark; 17.11.2015
comment
Ха-ха ой! Теперь я вижу проблему. Большое спасибо за ваше время :-) Как я могу получить доступ к инструменту тестирования UDF на будущее? - person GeorgeWilson; 18.11.2015
comment
Меня немного беспокоит то, что мой запрос публикуется здесь публично - не могли бы вы отредактировать свой ответ, чтобы удалить определенные имена/значения таблиц? - person GeorgeWilson; 18.11.2015
comment
Re: Редактировать - обязательно! LMK, если это выглядит нормально для вас сейчас. - person thomaspark; 19.11.2015
comment
Инструмент тестирования представляет собой простую форму на основе HTML: storage.googleapis. com/bigquery-udf-test-tool/testtool.html Это не идеальная замена для выполнения запросов в BQ, но она удобна для устранения неполадок. Если вы запустите его в Chrome, вы можете установить точки останова в своем коде через консоль разработчика. - person thomaspark; 19.11.2015
comment
Большой! Спасибо за вашу помощь, и редактирование выглядит хорошо. - person GeorgeWilson; 19.11.2015