ほくそ笑む

R言語と統計解析について

R から Teradata にクエリを投げる DBI 対応のパッケージ dplyr.teradata を作りました。

つくりました。まだ完成してないけど。

https://github.com/hoxo-m/dplyr.teradata

タイトルには「DBI 対応の」と断言していますが、テストはまだ通ってないので DBI に完全に準拠してるのか、そもそもそれは可能なのか、わかりません。。が、もう実装するの疲れたのでフライングで紹介します。

インストール

install_github() でインストールできます(CRAN に上げるにはまだまだ時間かかりそう)

devtools::install_github("hoxo-m/dplyr.teradata")

<追記> CRAN に上げました。install.packages() でインストールできます。

install.packages("dplyr.teradata")

使い方

dplyr.teradata のコネクションをつくるには driver、DBCName、uid、pwd、database を指定します。
database は省略可能です。

library(dplyr.teradata)

conn <- dbConnect(todbc(), driver = "{Teradata Driver}", 
                 DBCName = "localhost", uid = "*****", pwd = "*****")

さて、DBI ではコネクションに対してクエリを投げるための関数がいくつか用意されています。

  • dbSendQuery(): 結果ではなく DBIResult オブジェクトを返す。このオブジェクトを dbFetch() すると結果が得られる。
  • dbSendStatement(): 結果は返ってこない。INSERT とか UPDATE とかデータ操作系のクエリを投げるときはこれ。
  • dbGetQuery(): 結果が data.frame として返ってくる。

すぐに結果が欲しいなら使いたいのは dbGetQuery() でしょう。こんな感じです。

DBI::dbGetQuery(conn, "SELECT 1")
#>   1
#> 1 1

dplyr から使う(まだ実装中)

まだ実装中なんですけど、簡単な例なら動きます。R の data.frame を copy_to() でコピーしてみましょう。

copy_to(conn, iris, temporary = FALSE)

dbGetQuery() でなにかクエリを投げてみるとちゃんとデータがコピーできていることがわかります。

DBI::dbGetQuery(conn, "SELECT COUNT(*) FROM iris;")
#>   Count(*)
#> 1      150

dplyr では tbl() を使うと、データベースのデータを data.frame と同じように操作することができます。

teradata_iris <- tbl(conn, "iris")

中身を覗いてみます。ちゃんと iris ですね。(表示するだけだとデータベースへのアクセスが発生しないので中身は覗けないことに注意)。

teradata_iris %>% collect
#> # A tibble: 150 x 5
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>           <dbl>       <dbl>        <dbl>       <dbl>   <chr>
#>  1          5.1         3.5          1.4         0.2  setosa
#>  2          4.9         3.0          1.4         0.2  setosa
#>  3          4.7         3.2          1.3         0.2  setosa
#>  4          4.6         3.1          1.5         0.2  setosa
#>  5          5.0         3.6          1.4         0.2  setosa
#>  6          5.4         3.9          1.7         0.4  setosa
#>  7          4.6         3.4          1.4         0.3  setosa
#>  8          5.0         3.4          1.5         0.2  setosa
#>  9          4.4         2.9          1.4         0.2  setosa
#> 10          4.9         3.1          1.5         0.1  setosa
#> # ... with 140 more rows

これを %>% を使ってデータ操作していくことができます。

table %>% 
  select(Sepal.Length, Sepal.Width, Species) %>%
  group_by(Species) %>%
  summarise(x = sum(Sepal.Length)) %>%
  collect
#> # A tibble: 3 x 2
#>      Species     x
#>        <chr> <dbl>
#> 1     setosa 250.3
#> 2  virginica 329.4
#> 3 versicolor 296.8

ということで便利っぽいんですが、dplyr からちゃんと使えるようにするには SQL の変換用メソッドを実装する必要があります。この辺がまだできていないので、まだ複雑なクエリだとうまく動きません。たぶん。

sql_render() calls an SQL generation function (sql_select(), sql_join(), sql_subquery(), sql_semijoin() etc) to produce the actual SQL. Each of these functions is a generic, taking the connection as an argument, so that the details can be customised for different databases.
(https://cran.r-project.org/web/packages/dbplyr/vignettes/sql-translation.html)

Connection

RStudio Connections は読んでないけど、とりあえず「New connection」のところに Teradata が出てくるようにするのは odbc パッケージの方ですでに対応済みです。
新しくコネクションを開いたらタブに表示するようにする方(Connections Contract)もすでにできています。

TODO

  • dplyr に対応する。

最後に

ということでできていないことだらけなんですけど、たぶん単純に dbGetQuery() を使うだけなら問題なく使えると思います。Teradata から結果を抜いてきて R に入れるのに苦労してという人は使ってみてください。

使ってて変なところを見つけたり要望を閃いたりすれば、Twitter、このブログのコメント欄、GitHub の issues あたりでお知らせください。