55
2010/04/23 id: yssk22 (CouchDB-JP)

BPStudy32 CouchDB 再入門

Embed Size (px)

DESCRIPTION

CouchDB introduction at BPStudy.

Citation preview

Page 1: BPStudy32 CouchDB 再入門

2010/04/23

id: yssk22 (CouchDB-JP)

Page 2: BPStudy32 CouchDB 再入門

自己紹介

Yohei Sasaki (yssk22)

developerWorks のCouchDB連載記事

CouchDB基礎文法最速マスター

CouchDB-JP

People on the Couch: UTC+9

今年から某ECサイトの開発

Page 3: BPStudy32 CouchDB 再入門

はじめに / お願い

質問は随時... というのは大変なのでハッシュタグ #bpstudyを添えてつぶやいてください。

つぶやきに 半角?または全角? をいれていただければ回答します。

ハンズオン用URL

○ http://bit.ly/6rXbn5

Page 4: BPStudy32 CouchDB 再入門

目次

CouchDBとは何か?

HTTP API

MapReduce

CouchDB Application

Page 5: BPStudy32 CouchDB 再入門

まずは思想的な話から...

Page 6: BPStudy32 CouchDB 再入門

CouchDBとは何か?

KVSっぽいデータストア

Apache プロジェクト

HTTP によるアクセス

MapReduceでクエリができる

Erlangで実装されたデータベース

Lotus Notes みたいなレプリケーション

すべて正しいけれど、その前にもっと本質的な話を...

Page 7: BPStudy32 CouchDB 再入門

CouchDBの思想の原点: Relax

CouchDB: The Definitive Guide より... If there’s one phrase to describe CouchDB it is relax.

making CouchDB easy, event a pleasure, to use.

当たり前のことが当たり前に感じられる道具であること。

開発するときの当たり前感

○ ドキュメント指向

運用するときの当たり前感

○ いつでも利用可能

Page 8: BPStudy32 CouchDB 再入門

データモデルに対するアプローチ Webそのもの。 WWW はデータベース

WWW はドキュメント指向データベース

Django may be built for the Web, but CouchDB is built of the Web.

- Jacob Kaplan-Moss, Django Developer

Document Oriented Database Webで実現する文書そのものを格納するためのデータベース。

Page 9: BPStudy32 CouchDB 再入門

例:請求書

請求元: hogehoge株式会社請求先:

郵便番号: 123-4567

住所: 神奈川県川崎市...

氏名: 佐々木庸平

請求金額: \12,345

明細:

商品数量金額小計AAAA 1 1,980 1,980

BBBB 3 1,210 3,630

...

CouchDBにおける1つの保存単位- ドキュメント

Page 10: BPStudy32 CouchDB 再入門

例:請求書 (RDBの場合)

1, hogehoge株式会社

3, 123-4567, 神奈川県..., 佐々木庸平

10, 1, 1

10, 2, 31, AAAA, 1,980

2, BBBB, 1,210

請求元: 1

請求先: 3

請求金額: SUM(小計)

明細商品数量金額小計1 1 1.P 1 * 1.P

2 3 2.P 3 * 2.P

正規化!正規化!正規化!

Page 11: BPStudy32 CouchDB 再入門

正規化とドキュメント指向の狭間 正規化の利点はデータの整合性を保つこと。 例えば、請求書の発行後に住所が変わったら? 顧客マスタ上の住所を変更する あれ? 昔の請求書の住所までかわっちゃったんだけど...

現実世界の"ドキュメント"は整合性を保たないほうがよい場合も。 現実世界のとおりであることが当たり前 = Relax

Web を作るイメージでデザインするとしっくりくる。

1 URI = 1 ドキュメント

でも、マスタ管理はしたい。

Page 12: BPStudy32 CouchDB 再入門

ドキュメント指向的アプローチ請求元: hogehoge株式会社請求先:

郵便番号: 123-4567

住所: 神奈川県川崎市...

氏名: 佐々木庸平

請求金額: \12,345

明細:

商品数量金額小計AAAA 1 1,980 1,980

BBBB 3 1,210 3,630

...

hogehoge株式会社

佐々木庸平

AAAA, 1,980

BBBB, 1,210

台帳から書き写す、という事務処理

Page 13: BPStudy32 CouchDB 再入門

データモデルを定義するタイミング RDB

最初に蓄積すべきデータをモデル化しておく○ 業務分析

○ エンティティを切り出し

○ 正規化

○ 業務の決まりを事前定義

CouchDB

随時やる

業務の決まりを随時定義 現実世界で随時やるように...

Page 14: BPStudy32 CouchDB 再入門

スケールに対する考え方

CouchDBにとっての基幹システム ユーザーのブラウザ

Webのだめなところ レイテンシー ユーザーネットワークはSPoF

スケールダウンしても利用可能なサービスを提供する アプリケーションとデータ(のサブセット)を丸ごとユーザーに複製させる

Page 15: BPStudy32 CouchDB 再入門

通勤経路の稼働率

稼働率 24min/30min : 80%

具体的なサービスの例: gmail, google reader, twitter, hatena.ne.jp, ...

サービス提供側としては100%を目指しているのを十分承知しているものの...

Page 16: BPStudy32 CouchDB 再入門

レプリケーションによる可用性の確保ができるかもしれない

App

App

1台になっても、N台になっても対応できるストレージシステム

HTTP

Page 17: BPStudy32 CouchDB 再入門

ここまでのまとめ

CouchDB = Relax

当たり前のことを当たり前に。

データモデルに対するアプローチ

○ ドキュメント指向

スケールに対するアプローチ

○ スケールダウン

○ レプリケーション

Page 18: BPStudy32 CouchDB 再入門

実際の使い方

Page 19: BPStudy32 CouchDB 再入門

CouchDBの使い方

HTTP で使う 使い方 = Web で当たり前の使い方

○ GET : ドキュメントを取得する

○ POST : ドキュメントを作成する

○ PUT : ドキュメントを更新する

○ DELETE : ドキュメントを削除する

Web の常識をしっていれば、どの言語/ランタイムでもCouchDBは簡単○ 「Webを支える技術」参照

Page 20: BPStudy32 CouchDB 再入門

ドキュメントの表現方法

JSONで記述

すべてのドキュメントは一意に識別するためのIDとバージョン番号REVをもつ

他は自由

{

"_id" : "請求番号XXXXYYYY", "_rev" : "3-ZZZZZMMMM"

"発行者": "hogehoge株式会社"

"請求先": {

"郵便番号": 123-4567"

"住所": "神奈川県川崎市..."

"氏名": "佐々木庸平"

},

"請求金額": 12345

"明細": [

{ "商品: "AAAA", "数量": 1, "単価": 1980, "小計": 1980 },

...

]

}

Page 21: BPStudy32 CouchDB 再入門

Futon による確認

GUI Tool

http://localhost:5984/_utils/

Firefox + Firebug を使うのがbetter

デモ

Page 22: BPStudy32 CouchDB 再入門

補足: リビジョン管理

CouchDBはMVCCによりディスクアクセスを行う データの更新操作(PUT)は、論理更新であり物理的には追加が行われる。

_rev には"更新回数-ドキュメントのMD5" が格納されている

_rev を使った Optimistic Lock により更新の衝突を検出する

Compaction という操作により、古いリビジョンは削除される

Page 23: BPStudy32 CouchDB 再入門

HTTP API 一覧

後でリファレンス的に利用できるようにSphinx Document にまとめみました http://bit.ly/b008oP

HTTPメソッドは省略 慣習に従えばよいので。

○ XXを実行する 系はPOST

ハンズオンで curl を使って試します。

Page 24: BPStudy32 CouchDB 再入門

HTTP Header も活用しよう

Request X-Couch-Full-Commit

○ true

レスポンス前に確実にディスクに書き込む

- 帳票などのドキュメントに使う

○ false

ディスクに書き込む前に HTTP 201 を返す

- ポストイット的なドキュメントに使う

Response ETag

○ ドキュメントの _rev と同じ値が入る JSONのparseをしなくても_revを入手できる

Page 25: BPStudy32 CouchDB 再入門

そのほかの主要機能

レプリケーション 二つのデータベースの同期をとる

○ P2P モデルで、双方向に同期をとることができる。 半自動実行なので、ネットワークが切れても問題がない。

添付ファイル ドキュメントにはバイナリファイルを添付できる。○ メディア+メタデータ管理とかに利用可能

Page 26: BPStudy32 CouchDB 再入門

各種言語からの利用

HTTPライブラリとJSONライブラリが必要十分条件

以下独断と偏見によるおすすめ JavaScript

○ /_utils/script/jquery.couch.jsが標準添付

Ruby○ couchrest

Python○ couchdb-kit

○ python-couchdb

Java○ couchdb4j

Page 27: BPStudy32 CouchDB 再入門

データ処理のための手法...

Page 28: BPStudy32 CouchDB 再入門

デザインドキュメント

デザインドキュメント

CouchDBに格納されるアプリケーションを定義したドキュメント

ビュー

デザインドキュメントの中に定義するMapReduce関数を記述し、インデックスを作成する機能

Page 29: BPStudy32 CouchDB 再入門

デザインドキュメントの構成 {

"_id" : "_design/app",

"_rev" : "3-XXXXXX",

"language" : "text/javascript",

"views" : {

"count_by_name" : {

"map" : "function(doc){ ... }",

"reduce" : "function(k,v,r){ ... }"

}

},

"shows" : ...

"lists" : ...

}これ

Page 30: BPStudy32 CouchDB 再入門

ビューの用途

基本 ドキュメントのフィルタリング 並び替え 内部的にはインデックスを作る作業

○ ドキュメントを効率的に見つけるために!

様々な計算○ SUM とか。

応用 (データ構造の)フォーマット

○ "正規化", "非正規化" も含めて

覚えておくべきこと: クエリではありません。

○ "クエリ"の機能 ... URLにクエリ文字列っていうものがありますよね?

Page 31: BPStudy32 CouchDB 再入門

MapReduce

Map

1つのドキュメントから別のデータを作成する。

○ 別のデータ : Key-Value の組み合わせ

Reduce

Keyが同じデータの集合から、データを集約して1つの値を計算する。

○ reduce フェーズと rereduce フェーズがある

Page 32: BPStudy32 CouchDB 再入門

サンプルデータ

http://search.twitter.com/?q=%23bpstudy

{

"_id": "479ce1c32f79d7864730ecbae60d6610",

"_rev": "1-f45bf5f71b84692d0acc4b196849c2d7",

"iso_language_code": "ja",

"type": "tweets",

"keyword": "#bpstudy",

"text": "1時間遅れたけど終わった。これであとは資料の残り半分を完成させればOK

#bpstudy (といってハッシュタグのテスト)",

"created_at": "Sat, 17 Apr 2010 19:07:16 +0000",

"profile_image_url":

"http://a3.twimg.com/profile_images/427387065/speedland_normal.png",

"source": "<ahref="http://sites.google.com/site/yorufukurou/"

rel="nofollow">YoruFukurou</a>",

"from_user": "yssk22",

"from_user_id": 3749810,

"to_user_id": null, "geo": null, "id": 12356675615,

"metadata": { "result_type": "recent" }

}

ハンズオンでやります。

Page 33: BPStudy32 CouchDB 再入門

map 関数 の書き方

function(doc){

emit(key, value);

emit(key, value);

...

}

emit(key, value)

Page 34: BPStudy32 CouchDB 再入門

発言者ごとにemitする

function(doc){function format_date() { ... }; // 省略if( doc.type == ''tweets'' ){

var t = format_date(t);emit([doc.from_user, t],

null);}

}

emit(key, value) で出力を定義 key はobject以外の任意の値 value は null でもよい。

○ undefined はJSONの仕様外なのでだめ

Page 35: BPStudy32 CouchDB 再入門

結果

/{db}/_design/{app} /_view/{viewname}

で確認可能

{"total_rows":169,"offset":0,"rows":[

{"id":"...","key":["AE35","2010/04/02 01:36"],"value":null},

{"id":"...","key":["albuk","2010/04/01 15:36"],"value":null},

{"id":"...","key":["ali_lin5757","2010/04/05 20:02"],"value":null},

{"id":"...","key":["Amoreeeee","2010/04/06 15:45"],"value":null},

{"id":"...","key":["aodag","2010/04/02 01:57"],"value":null},

...

]}

Page 36: BPStudy32 CouchDB 再入門

ビューに対してクエリをかける よく使うのは範囲指定 startkey=xxx&endkey=yyyy

特定の発言者だけ時系列にとりだす startkey=["yssk22"]&

endkey=["yssk22", "\u9999"]

○ ["yssk22"] より大きくて、["yssk22", "\u9999"] より小さいキーを抽出 配列は要素ごとに比較して順序づけ

文字列の最大値は \u9999

Page 37: BPStudy32 CouchDB 再入門

CouchDBのMapReduceの特徴 B+Tree構造でディスクに結果を保持

インクリメンタルに実行される

一度計算した結果は、元のドキュメントが更新されない限りキャッシュが保持される。

Page 38: BPStudy32 CouchDB 再入門

CouchDBのMapReduceの特徴 B+Tree構造でディスクに結果を保持

インクリメンタルに実行される

一度計算した結果は、元のドキュメントが更新されない限りキャッシュが保持される。

オンラインシステムで使えるMapReduceの仕組み

再計算しない 再計算しない再計算する再計算しない

更新

Page 39: BPStudy32 CouchDB 再入門

発言数をカウントする

map 関数の定義

function(doc){

function format_date() { ... }; // 省略if( doc.type == ''tweets'' ){

var t = format_date(t);

emit([doc.from_user, t],

1);

}

}

Page 40: BPStudy32 CouchDB 再入門

発言数をカウントする

reduce 関数の定義

function(keys, values, rereduce){

if( rereduce ){

return sum(values); // sum([2,5,3,4, ...])

}else{

return values.length; // [1,1,1,1,...].length

}

}

Page 41: BPStudy32 CouchDB 再入門

rereduce に注意

rereduce()

reduce()

MapReduceの実行モデル

Page 42: BPStudy32 CouchDB 再入門

Rereduceに注意

これは正しく動かない場合がある function(key, values, rereduce){

return values.length;}

これは正しく動くが遅い場合がある function(key, values, rereduce){

return sum(values);}

reduce 結果のデータ構造は意識して計算を記述する

Page 43: BPStudy32 CouchDB 再入門

アプリケーションとデータベースの奇妙な関係

Page 44: BPStudy32 CouchDB 再入門

ちょっと前のWeb+DB

Web Server Web Server Web Server Web Server

App Server App Server App Server App Server

RDB Server RDB Server

Page 45: BPStudy32 CouchDB 再入門

最近の Web+DB

Web Server Web Server Web Server Web Server

App Server App Server App Server App Server

DB Server DB Server DB Server DB Server

RDBだったりKVSだったり...

Page 46: BPStudy32 CouchDB 再入門

CouchDB = 1人で3役

Relax Relax Relax Relax

Page 47: BPStudy32 CouchDB 再入門

CouchDBはWebを作るデータベース Webを作るのに必要な機能を一通りもっている。

HTTPリクエストに対して、以下の振る舞いを提供する

静的なデータを返す

HTTP API

動的なデータを返す

Show, List 関数

適切な振り分けを行う

Virtual Host, URL Rewrite

適切にデータを更新する

HTTP API, Update 関数, Validation 関数

Page 48: BPStudy32 CouchDB 再入門

再びデザインドキュメント

{

"_id" : "_design/app",

"_rev" : "3-XXXXXX",

"language" : "text/javascript",

"views" : ...

"shows" : {

"tweet": "function(doc, req){ ... }"

}

"lists" : {

"timeline": "function(head, req){...}"

}

}

これ

Page 49: BPStudy32 CouchDB 再入門

Show関数

ドキュメントを表示する. /{db}/_design/{app} /_show/{showname}/{doc_id}

○ doc_idは Optional

JavaScript で記述 ... !?

Server Side JavaScript.

Page 50: BPStudy32 CouchDB 再入門

tweet の表示

function(doc, req){

var t = require('vendor/crayon/lib/template');if(doc &&doc.type == 'tweets'){

bindings["page.title"] = "@" + doc.from_user + ": " + doc.text;

bindings["tweet.id"] = doc.id;

bindings["tweet.text"] = doc.text;

...

returnt.render(ddoc.templates.site.header, bindings) +

t.render(ddoc.templates.tweet, bindings) +

t.render(ddoc.templates.site.footer, bindings);

}

...

URLからドキュメントを変数にマップ

3rd party ライブラリの利用

コンテンツを文字列で返す

Page 51: BPStudy32 CouchDB 再入門

List関数

Viewの結果を表示する. /{db}/_design/{app} /_list/{listname}/{viewname}

○ viewnameは 必須

○ クエリ文字列も利用可能

例によってJavaScript で記述

Server Side JavaScript.

Page 52: BPStudy32 CouchDB 再入門

timeline の表示

function(head, req){

provides(''html", function(){

bindings["page.title"] = keyword;

send(t.render(ddoc.templates.site.header, bindings));

send(t.render(ddoc.templates.timeline.header, bindings));

while(row = getRow()){

var doc = row.doc;

if( doc &&doc.type == 'tweets'){

$.extend(bindings, h.bind_tweet(doc));

send(t.render(ddoc.templates.timeline.row, bindings));

}

}

send(t.render(ddoc.templates.timeline.footer, bindings));

return t.render(ddoc.templates.site.footer, bindings);

});

}

Content-Length: chunked で送信開始

Content Negotiation

Viewの結果を1行ずつ取得して処理

Page 53: BPStudy32 CouchDB 再入門

CouchDBで実装したオンラインTV録画システム

http://bit.ly/bX5i7Q

ソース:

http://github.com/yssk22/recstore

世界中のCouchDBソフトウェアはCouchDB wiki を参照。

Page 54: BPStudy32 CouchDB 再入門

Server Side JavaScript Impl

CouchDBの場合は Spidermonkeyベースの実装

CGIのように動作する couchjsというProcess Poolが都度実行

○ CouchDBのメインプロセスとPipeで通信

それほど早くないので注意○ Server Side で実装してみて、遅ければブラウザに実行させ

るのもあり。 ドキュメントモデルと画面の差異が大きいほどJSで処理する量が多

くなるので、その場合は設計を疑うのも○。

実際どこまでできる? sandbox になっているので、ファイルを読んだり、外部リ

ソースにアクセスすることはできない。 JSの実装が気に入らなければ、Python, Ruby など他の実装

に切り替えることもできる。

Page 55: BPStudy32 CouchDB 再入門

まとめ

CouchDBとは、Webの一部となるドキュメント指向データベース

Web を支える HTTP で操作される

データベースとアプリケーションサーバーがJavaScriptで完結する

time to relax.