Использование пользовательских функций JavaScript внутри BigQuery для вычисления Фибоначчи
BigQuery имеет удобную функциональность для поддержки пользовательских функций, написанных на SQL и JavaScript, поэтому я подумал, что было бы интересно решить небольшую проблему с числами Фибоначчи.
Я почти уверен, что видел эту задачу в Project Euler или в чем-то подобном, поэтому, пожалуйста, не используйте это как способ обмана. Задача заключается в следующем:
Найдите сумму последних 6 шести цифр для первых 1000 чисел Фибоначчи. Это может показаться немного сложным, поэтому мы начнем медленно с вычисления полных чисел Фибоначчи, а затем продолжим.
Что такое последовательность Фибоначчи?
Последовательность определяется как:
- a(0) = 0
- a(1) = 1
- a(n) = a(n-2) + a(n-1)
Итак, каждый элемент является суммой двух предыдущих. Вот он в действии:
0, 1, 1, 2, 3, 5, 8, 13, 21…
Как вы понимаете, эти числа могут довольно быстро стать довольно большими. Например, 50-е число - 12,586,269,025, что больше 12 миллиардов, с буквой b! (100-е число: 354,224,848,179,261,915,075 😬)
Как, черт возьми, мы это делаем в BigQuery?
Теперь, когда мы знаем, что такое ряд Фибоначчи, возникает очевидный вопрос, как создать цикл в BigQuery. Что ж, есть способы сделать это с помощью сценариев BigQuery, но здесь я буду использовать вместо этого пользовательские функции JavaScript.
Вот функция JavaScript для вычисления n-го числа Фибоначчи:
Я знаю JavaScript от нуля до нуля, поэтому, пожалуйста, напишите мне в комментариях, если я делаю здесь что-то глупое!
Вот оно в действии, если вы хотите поиграть с ним.
Время использовать функцию
Чтобы создать эту функцию в BigQuery, нам нужно использовать объявление CREATE TEMP FUNCTION
:
Мы можем использовать то же тело функции JavaScript, что и выше. Все, что нам нужно сделать, это удалить бит function fib(n)
из бита JavaScript и добавить типы ввода и вывода в бит SQL. Обратите внимание, как мы говорим fibonacci(n INT64)
, чтобы объявить, что ввод должен быть целым числом, и RETURNS INT64
, чтобы указать тип вывода.
Давайте возьмем цифры в BigQuery:
Если вы не знаете, что происходит с генератором массивов и отменой вложенности в with
statement, ознакомьтесь с моей статьей FizzBuzz с BigQuery 🍾 - там все объясняется.
Вот результаты:
╔═════╦═════╦═════════════╗ ║ Row ║ num ║ fib_n ║ ╠═════╬═════╬═════════════╣ ║ 1 ║ 0 ║ 0 ║ ║ 2 ║ 1 ║ 1 ║ ║ 3 ║ 2 ║ 1 ║ ║ 4 ║ 3 ║ 2 ║ ║ 5 ║ 4 ║ 3 ║ ║ 6 ║ 5 ║ 5 ║ ║ 7 ║ 6 ║ 8 ║ ║ 8 ║ 7 ║ 13 ║ ║ 9 ║ 8 ║ 21 ║ ║ 10 ║ 9 ║ 34 ║ ║ 11 ║ 10 ║ 55 ║ ║ 12 ║ 20 ║ 6765 ║ ║ 13 ║ 30 ║ 832040 ║ ║ 14 ║ 40 ║ 102334155 ║ ║ 15 ║ 50 ║ 12586269025 ║ ╚═════╩═════╩═════════════╝
Это заняло 0,5 секунды. Не так уж и плохо, и похоже, что он работает нормально, так как у нас есть тот же 50-й элемент, что и выше.
Теперь настоящий вызов
Если вы вернетесь к началу, то увидите, что первоначальной задачей было вычислить сумму последних 6 цифр для первых 1000 чисел Фибоначчи. Теперь это будет легко. Хитрость здесь в том, чтобы понять, что для точного вычисления последних 6 цифр вам нужны только последние 6 цифр, поэтому мы можем выбросить остальные, используя оператор по модулю. Нам нужен этот трюк, иначе наш INT64
станет слишком большим и переполнится.
Нам просто нужно добавить: var new_num = (numbers[0] + numbers[1]) % 1000000;
в нашу функцию JavaScript, а затем просуммировать все результаты. Вот для этого SQL:
Это работало за 0,9 секунды, так что BigQuery сейчас действительно потеет ... И результат:
╔═════╦═══════════╗ ║ Row ║ result ║ ╠═════╬═══════════╣ ║ 1 ║ 477632375 ║ ╚═════╩═══════════╝
Я бы порекомендовал вам изменить приведенный выше SQL и посмотреть на последние 6 цифр сотого числа Фибоначчи, чтобы убедиться, что это правильно!
Подведение итогов
Подводя итог, можно сказать, что функции JavaScript действительно легко добавить в BigQuery, и вы можете вместе провести несколько интересных вычислений. Более того, вы даже можете использовать библиотеки JavaScript, если включите файл .js
в корзину Google Cloud Storage. Как это круто?