Google、ビッグデータ分析サービス「BigQuery」を一般公開 - ITmedia ニュースサンプルデータも幾つかある様で、githubのリポジトリ情報を格納している物もあったので試しにGo言語からクエリを発行して問い合わせてみた。 以下コード。
米Googleは11月14日(現地時間)、同社のクラウド上でいわゆる「ビッグデータ」を分析する企業向けサービス「Google BigQuery Service」のプレビュー版を公開したと発表した。正式版は有料になる見込みだが、現在は無料で利用できる。
http://www.itmedia.co.jp/news/articles/1111/15/news028.html
package main
import (
"code.google.com/p/goauth2/oauth"
"code.google.com/p/google-api-go-client/bigquery/v2"
"encoding/gob"
"fmt"
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
"path/filepath"
"runtime"
"time"
)
func osUserCacheDir() string {
switch runtime.GOOS {
case "darwin":
return filepath.Join(os.Getenv("HOME"), "Library", "Caches")
case "linux", "freebsd":
return filepath.Join(os.Getenv("HOME"), ".cache")
}
log.Printf("TODO: osUserCacheDir on GOOS %q", runtime.GOOS)
return "."
}
func tokenFromWeb(config *oauth.Config) *oauth.Token {
ch := make(chan string)
randState := fmt.Sprintf("st%d", time.Now())
ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/favicon.ico" {
http.Error(rw, "", 404)
return
}
if req.FormValue("state") != randState {
log.Printf("State doesn't match: req = %#v", req)
http.Error(rw, "", 500)
return
}
if code := req.FormValue("code"); code != "" {
fmt.Fprintf(rw, "<h1>Success</h1>Authorized.")
rw.(http.Flusher).Flush()
ch <- code
return
}
log.Printf("no code")
http.Error(rw, "", 500)
}))
defer ts.Close()
config.RedirectURL = ts.URL
authUrl := config.AuthCodeURL(randState)
go openUrl(authUrl)
log.Printf("Authorize this app at: %s", authUrl)
code := <-ch
log.Printf("Got code: %s", code)
t := &oauth.Transport{
Config: config,
Transport: http.DefaultTransport,
}
_, err := t.Exchange(code)
if err != nil {
log.Fatalf("Token exchange error: %v", err)
}
return t.Token
}
func openUrl(url string) {
try := []string{"xdg-open", "google-chrome", "open"}
for _, bin := range try {
err := exec.Command(bin, url).Run()
if err == nil {
return
}
}
log.Printf("Error opening URL in browser.")
}
func tokenCacheFile(config *oauth.Config) string {
return filepath.Join(osUserCacheDir(), url.QueryEscape(
fmt.Sprintf("go-api-demo-%s-%s-%s", config.ClientId, config.ClientSecret, config.Scope)))
}
func tokenFromFile(file string) (*oauth.Token, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
t := new(oauth.Token)
err = gob.NewDecoder(f).Decode(t)
return t, err
}
func saveToken(file string, token *oauth.Token) {
f, err := os.Create(file)
if err != nil {
log.Printf("Warning: failed to cache oauth token: %v", err)
return
}
defer f.Close()
gob.NewEncoder(f).Encode(token)
}
func getOAuthClient(config *oauth.Config) *http.Client {
cacheFile := tokenCacheFile(config)
token, err := tokenFromFile(cacheFile)
if err != nil {
token = tokenFromWeb(config)
saveToken(cacheFile, token)
} else {
log.Printf("Using cached token %#v from %q", token, cacheFile)
}
t := &oauth.Transport{
Token: token,
Config: config,
Transport: http.DefaultTransport,
}
return t.Client()
}
func main() {
var config = &oauth.Config{
ClientId: "XXXXXXXXXXXXX.apps.googleusercontent.com",
ClientSecret: "YYYYYYYYYYYYYYYYYYYYYYYY",
Scope: bigquery.BigqueryScope,
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
}
bigqueryService, err := bigquery.New(getOAuthClient(config))
if err == nil {
table, err := bigqueryService.Jobs.Query("XXXXXXXXXXXXX", &bigquery.QueryRequest {
Query: "SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'",
}).Do()
if err == nil {
for _, row := range table.Rows {
for _, f := range row.F {
println(f.V)
}
}
}
}
}
XXXXXXXXXXXXX にはプロジェクトIDを(ClientIDの一部になってるみたい)、YYYYYYYYYYYYYYYYYYYYYYYY には ClientSecret を埋めて実行して下さい。発行しているクエリは以下。
SELECT repository_description FROM [publicdata:samples.github_timeline] where repository_url = 'https://github.com/mattn/growl-for-linux'
これを実行すると以下のデータが得られた。
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
Growl Implementation For Linux #growl4linux
実行はそれほど速くありませんでした。巨大なデータをオンラインで扱えるインフラとしては面白いかなーと思った。ただ最近の API は OAuth な物が多く、実行するにはアクセストークンが必要になり、アクセストークンを得るにはブラウザを起動する必要がある。今回 Go言語のdatabase/sqlドライバの一つに加えようと思ってけどちょっと難しいかも。どっちかっていうとユーザ単位にアクセストークンを取らせる様なコンシューマサービス向けなのかな。