14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

トレタAdvent Calendar 2017

Day 8

そうだ Lisp 作ろう (Make a Lisp in Google BigQuery)

Last updated at Posted at 2017-12-08

こんにちは、トレタ Advent Calendar 2017の8日目記事です。

トレタでは膨大なデータを分析する際に Google BigQuery を使ってますが、今年はデータサイエンティストチームも立ち上がってより大規模な分析が可能になりました。

さてさて、お硬い話は置いといて。クリスマス前なので、ここでは何か面白おかしい SQL 芸でもしましょう。BigQuery は JavaScript ベースのユーザー定義の関数(UDF)をサポートしています、つまり必要であれば好き勝手に UDF で BigQuery の関数を拡張することができます。この際 UDF を使って別の言語を実装して BigQuery のなかで呼び出しましょう!!

イメージ

イメージとしては SQL でこんな呼び出しをできたら面白いと思います。

select mal('(fn* [a b c] (reduce + 0 [a b c]))', [1.1, 2.2, 3.3])

内部はコードを read 関数で AST に変換して、 eval 関数で環境と共に評価します。

Screen Shot 2017-12-07 at 17.17.11.png

Make a Lisp (mal)

今回は Make a Lisp (mal) という Lisp 系の処理系をもとに実装してみようというプロジェクトです。mal の特徴といえば説明が詳しく、多くの言語(現時点で71言語)での実装例を参考にすることが可能です。

内部実装はほとんど mal の JavaScript 実装例を持ってきましたが、Node.js や Browser の環境と異なるため、モジュール周りは変更して、console オヴジェクトがないため prn 系の関数も除外してます。

Screen Shot 2017-12-07 at 17.35.07.png Source: https://github.com/kanaka/mal/blob/master/process/guide.md#stepA

完成したコードはこちらに公開しております。
https://github.com/hden/mal

UDF 周り

BigQuery の UDF は基本こんな構造になってますが

create temporary function multiplyInputs(x int64, y int64)
returns int64
language js as """
  return x * y
""";

OPTIONS セクションを付けることで GCS 上の外部コード、またはライブラリを読み込むことが可能です。例えば自分の gs://hden/mal/ バケット内にコードを置くと

#standardsql
create temporary function mal (str string, args array<float64>)
  returns float64
  language js as 'return mal.apply(str, args)'
  options (
    library=['gs://hden/mal/bundle.js']
  )
;

こういう風に読み込むことが可能です。

データ型

BigQuery の int 型は基本 int64 ですが、 JavaScript に int64 はないので文字列として渡されます、parseInt() などの関数である程度丸め込むことが可能ですが、注意が必要です。

データ型のマッピングはこちらです。
https://cloud.google.com/bigquery/sql-reference/user-defined-functions?hl=ja#sql-type-encodings-in-javascript

最後に

楽しんでいただけたでしょうか?

#standardsql
create temporary function mal (str string, args array<float64>)
  returns float64
  language js as 'return mal.apply(str, args)'
  options (
    library=['gs://hden/mal/bundle.js']
  )
;
select mal('(fn* [a b c] (reduce + 0 [a b c]))', [1.1, 2.2, 3.3])

では皆さん、良いクリスマスを。

14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?