2012/05/02


BigQueryが正式版としてリリースされたようです。
Google、ビッグデータ分析サービス「BigQuery」を一般公開 - ITmedia ニュース

米Googleは11月14日(現地時間)、同社のクラウド上でいわゆる「ビッグデータ」を分析する企業向けサービス「Google BigQuery Service」のプレビュー版を公開したと発表した。正式版は有料になる見込みだが、現在は無料で利用できる。

http://www.itmedia.co.jp/news/articles/1111/15/news028.html
サンプルデータも幾つかある様で、githubのリポジトリ情報を格納している物もあったので試しにGo言語からクエリを発行して問い合わせてみた。 以下コード。 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ドライバの一つに加えようと思ってけどちょっと難しいかも。どっちかっていうとユーザ単位にアクセストークンを取らせる様なコンシューマサービス向けなのかな。
Posted at by



2012/03/29


ようやくリリースされました!
go1 released

We've just tagged a new Go release: go1.
Go 1 is a major release of Go that will be stable in the long term.
It is intended that programs written for Go 1 will continue to compile
and run correctly, unchanged, under future versions of Go 1.

The Go 1 release notes list the significant changes since the last
release and explain how to update your code:
        http://golang.org/doc/go1.html

To learn about the future of Go 1, read the Go 1 compatibility document:
        http://golang.org/doc/go1compat.html

Go 1 is available as binary distributions for the
FreeBSD, Linux, Mac OS X, and Windows operating systems.
To install a binary distribution, follow these instructions:
        http://golang.org/doc/install

If you prefer to build from source, follow these instructions:
        http://golang.org/doc/install/source

The Go team would like to thank all our contributors from the open
source community. We could not have done it without their help.
See the full list of contributors here: http://golang.org/CONTRIBUTORS

We also thank our users. We hope you enjoy Go 1.

Have fun. (And tell your friends! ;-)

Andrew

https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/fVonEtwNSFc
初めてgo言語を触った時、C++よりも型が柔らかく、ネイティブコードへのコンパイル型言語なのにダックタイピングやgcを備える非常に柔軟な言語に感動を覚えました。いろんな可能性を秘めているし、C++よりも簡単なコードで立派なアプリケーションが書ける。そう思いました。(もちろんC++も大好きです)
リリースまでに送ったパッチは56個でした。主にWindowsのAPI周り、HTTPプロキシ処理の初期実装やソケットサーバのバグ修正、特に他のOSで先に実装された機能のWindows版の実装などをお手伝い出来ました。
golang-devチームにとっても僕にとってもgo1 releaseは一つの区切りでしか無いでしょう。今後もまた、パッチを送りつづけるでしょう。

質の高い言語をこんなにも短期でリリースしてしまったgolang-devチームに拍手を送りたいと思います。
Posted at by



2012/03/23


そう言えば、go言語版を書いてなかったなーと思ったのでエントリ。
いかにしておっぱい画像をダウンロードするか?2012 - ゆーすけべー日記

4年以上前のBlog記事で非常に評判がよく「高校生がプログラミングをはじめるキッカケになった」というエントリーがあります。 題名は「 いかにして効率よく大量のおっぱい画像をダウンロードするか 」。 僕...

http://yusukebe.com/archives/20120229/072808.html
こういう並行処理を簡単に書けてネイティブ実行出来るgo言語はやっぱり素晴らしいなぁと思いました。
# oppai [appid] [outdir] [keyword]
といった感じにお使い下さい。 package main

import (
    "crypto/md5"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "os"
    "path/filepath"
    "strconv"
    "strings"
)

type response struct {
    SearchResponse struct {
        Image struct {
            Results []struct {
                MediaUrl    string
                ContentType string
            }
        }
    }
}

func main() {
    if len(os.Args) != 4 {
        println("usage: oppai [appid] [outdir] [keyword]")
        os.Exit(1)
    }
    appid, outdir, keyword := os.Args[1], os.Args[2], os.Args[3]

    total := 0
    offset := 0
    outdir, _ = filepath.Abs(outdir)
    param := url.Values{
        "AppId":       {appid},
        "Version":     {"2.2"},
        "Market":      {"ja-JP"},
        "Sources":     {"Image"},
        "Image.Count": {strconv.Itoa(50)},
        "Adult":       {"off"},
        "Query":       {keyword},
    }
    quit := make(chan bool)

    md5hash := md5.New()
    to_filename := func(s, t stringstring {
        md5hash.Reset()
        md5hash.Write([]byte(s))
        token := strings.SplitN(t, "/"2)
        if strings.Index(token[1], "jpeg") != -1 {
            token[1] = "jpg"
        }
        return fmt.Sprintf("%X.%s", md5hash.Sum(nil), token[1])
    }

    for {
        param["Image.Offset"] = []string{strconv.Itoa(offset)}
        res, err := http.Get("http://api.bing.net/json.aspx?" +
            param.Encode())
        count := 0
        if err == nil {
            var result *response
            err = json.NewDecoder(res.Body).Decode(&result)
            res.Body.Close()
            if err != nil {
                println(err.Error())
                break
            }
            if count = len(result.SearchResponse.Image.Results); count ==
                0 {
                total = -1
                break
            }
            for _, r := range result.SearchResponse.Image.Results {
                go func(url, ct string) {
                    filename := filepath.Join(outdir, to_filename(url, ct))
                    if f, derr := os.Create(filename); derr == nil {
                        defer f.Close()
                        dres, derr := http.Get(url)
                        if derr == nil && dres.ContentLength > 0 &&
                            strings.Index(dres.Header.Get("Content-Type"), "image/") == 0 {
                            _, derr = io.CopyN(f, dres.Body, dres.ContentLength)
                            if derr != nil {
                                println(derr.Error())
                            } else {
                                println(filename)
                            }
                        }
                    }
                    quit <- false
                }(r.MediaUrl, r.ContentType)
            }
        } else {
            total = -1
            break
        }
        offset += count
        total += count
    }

    for total > 0 {
        <-quit
        total--
        println(total)
    }
}
けしからんけしからん。
追記1
終了を待ってなかった。 ...orz

追記2
ちょっとエラー処理足した。

Go言語プログラミング入門on Google App Engine Go言語プログラミング入門on Google App Engine
横山 隆司
秀和システム 単行本 / ¥151 (2011年12月14日)
 
発送可能時間:

はじめての「Go言語」: Googleが提供する高速コンパイラ言語 (I/O BOOKS) はじめての「Go言語」: Googleが提供する高速コンパイラ言語 (I/O BOOKS)
茨木 隆彰
工学社 単行本 / ¥2,090 (2010年11月01日)
 
発送可能時間:

Posted at by