第2回 さくさくテキストマイニング勉強会に行ってきた
前回に引き続き、「第2回 さくさくテキストマイニング勉強会」に参加してきました。
会場は前回と同じOracle青山センターです。200人ぐらい入る大きな会議室。さすがです。
目的&概要
目的
テキストマイニングについての学習のスタートアップ
テキストマイニング技術に関して気軽に参加・議論することができる場の提供
概要テキストマイニングとは、例えば製品の評判をweb上のテキストから抽出したり、
大量のアンケートテキストを分析するために用いられる技術であり、特にマーケティングの場で多くの利用例があります。この勉強会ではそうしたテキストマイニングを題材とし、用いられている要素技術とそれに関わる課題の議論、
第2回「にこにこ」改め さくさくテキストマイニング勉強会
またテキストマイニングを実務に活かす方法について考えていきます。
言語処理学会へ遊びに行ったよ〜不自然言語処理へのお誘い〜 [twitter:@AntiBayesian]
資料は ここ(PDF) から。
- 顔文字情報と文の評価表現の関連性についての一考察
- 顔文字は周辺言語的要素を持つ
- 顔文字単体での極性だけではなく、文脈把握が大切
- 顔文字は回答者によって、快・不快バラバラ
- 極性が異なるのに同じ顔文字が使われることも
- クラス分類ではなく、複数の感情軸を併せ持つ
- 自身は意味を持たず、強調、緩衝材としての顔文字利用
- どんな時に不自然言語を使うか?
- 仲の良い人同士だと砕けた表現や隠語使いやすい
- 他の人より頻繁に不自然言語を用いて会話する相手=仲が良いのでは?ソーシャルネットワーク抽出出来る
- 不自然言語の利用度合いが親密さを表すかも
- 顔文字は非言語的な情報まで伝達出来るかも
- 誤字・脱字から精神状態などを読み取れるかも
- 誤った語の使い方から年齢等が推定できるかも
必ずチェックすべき10のブログ (下に行く程、難しい内容らしい。上から5つぐらいは読むべし)
- コーパスいぢり( [twitter:@langstat] )
- あらびき日記( [twitter:@a_bicky] )
- 睡眠不足?( [twitter:@sleepy_yoshi] )
- EchizenBlog-Zwei( [twitter:@echizen_tm] )
- Overlasting::Life( [twitter:@overlast] )
- おとうさんの解析日記( [twitter:@isseing333] )
- はやしのブログRev.2( [twitter:@phosphor_m] )
- nokunoの日記( [twitter:@nokuno] )
- ぬいぐるみライフ(仮)( [twitter:@mickey24] )
- Mi manca qualche giovedi`( [twitter:@shuyo] )
今日から使える! みんなのクラスタリング超入門 [twitter:@toilet_lunch]
非階層型、ハードクラスタリングの手法 k-meansについてのお話。
- bayon
- Repeated Bisection法
- k-meansでもクラスタリングできる
- 商用利用で事前許可が不要
- x-means
- k-meansのクラスタの数を推定してくれる
『可視化するだけ』でも面白い テキストマイニング最初の一歩 [twitter:@ts_3156]
えごったー の中の人の発表。
- えごったー
- 高度な知識は必ずしも必要ない
- 今回利用したのは、形態素解析だけ
- 簡単な解法で解ける問題もたくさんある
- 可視化するだけでもよい、面白さは人が勝手に見つける
- えごったー側で行うのは簡単な情報の提示のみ
- 意味を汲み取るのは人間の役目
- 面白い可視化の例
見切り発車でも大丈夫。とりあえず作ってみよう
概観テキストマイニング [twitter:@todesking]
- 大量のデータ
- 人間ではハンドリングできない程に多いデータを相手にする
- 統計的手法はデータが多いほうが有効
- 計算機の出番
- フリーテキスト
- 自然言語による記述
- 構造化されていないデータ
- さまざまなノイズ
- 表記ゆれ
- 未知の表現
- 計算機で処理するには工夫が必要
- 前処理必須
- 解析ミスがつきもの
- なぜフリーテキストなのか?
- データ量はパワーである
- ノイズ混じりだが大量のデータを入手可能
- 事前に構造を規定しなくていい
- フリーテキストの構造を分析する
- ノイズとの戦い
- 未知の用語
- 誤記
- ノイズとの戦い
- テキストマイニングでいかに価値を生むか
- その分析結果が何を意味するのか?
- 次にすべき行動は?
- その行動は誰に、どのような価値をもたらすか?
WordNetで作ろう! 言語横断検索サービス [twitter:@stakemura]
社内google code を作りたいが、増え続けるプログラムをすぐに見つからない状態をなんとかしたい。
- 検索機能を強化
- 日英表記揺れを解決
- 語義曖昧性を解決
検索結果がよろしくない。
- BM25Fでやっと納得のいく結果が得られた
- 自作の検索エンジンなのですぐ対応できた
togetter [twitter:@kimukou_26]
MongoDBのShardingを試してみた。その2 Migration中の挙動について
Sharding環境にて、shard keyを使用しない以下のクエリに問題があることが知られている。
(第2回MongoDB勉強会の@doryokujinさんの発表参照。私の参加日記は ここ から)
- Chunk Migration中のcount
- 同時書き込み発生時のsingle-update()
- 同時書き込み発生時のunique index
- tmp_collectionが削除されないmapreduce
今回は、Sharding環境にて、chunkのMigration中の各クエリの挙動について検証します。
同時書き込みの発生再現は、難しいので今回は割愛します。
この検証では、mongodb 1.8.0を使用しています。
構成については、 MongoDBのShardingを試してみた。その1 を参照
Chunk Migration中のcount
原因
- Chunk Migration中は処理が完了するまで、移動元、移動先に同じchunkが存在する。
- 完全にコピーが完了し、configサーバが更新されて完了となる。
検証
まずは、意図的にchunkの偏りを発生させます。
sharding設定前に100万件程のアクセスログを投入し、確認していこうかと思います。
[matsuou1@testsvr mongodb]$ ./bin/mongoimport -h localhost:10001 -d logdb -c logs10 --ignoreBlanks --type tsv --fields month,uid,timestamp,path,device /tmp/ mongodb/work/access_201003.log connected to: localhost:10001 (略) imported 946611 objects
shardingの設定を行い、chunkの分散を確認します。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/logdb MongoDB shell version: 1.8.0 connecting to: localhost:10000/logdb > db.logs10.count(); 946611 > db.logs10.ensureIndex( { uid : 1 } ); > use admin switched to db admin > db.runCommand( { shardcollection : "logdb.logs10" , key : { uid : 1 } } ); { "collectionsharded" : "logdb.logs10", "ok" : 1 } > db.printShardingStatus(); (略) logdb.logs10 chunks: shard0001 1 shard0002 1 shard0000 266 too many chunksn to print, use verbose if you want to force print > db.printShardingStatus(); (略) logdb.logs10 chunks: shard0001 25 shard0002 25 shard0000 218
最初、shard0000にあった全てのchunkが、shard0001、shard0002にmigrationが行われ、平準化されています。
全て平準化される前に、countを実施するとchunk migration途中のchunkが重複カウントされ、正しい値より大きな値が表示されるはず。
とりあえず、shard keyではないtimestampを条件にしたcountを10秒に1回程度実行してみましょう。
> db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285133 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285108 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285120 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285047 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285128 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285140 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284984 ★ > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 284078 > db.logs10.find( { timestamp : {$gt : "2010/03/10 00:00:00" , $lt : "2010/03/20 00:00:00" } } ).count(); 285153 ★
まとめ
★がついている個所が、正しい値(284078)より多い数値が表示された。
表示される値は都度異なり、重複カウントされるchunkに依存する。
25回中6回、不正な値が出力された。約25%なので、migration中はかなりの確率で発生しうると言える。
運用中のchunk migration時にも気をつける必要があるが、single構成からsharding構成に変更する際も当然注意が必要。
MongoDBのShardingを試してみた。その1
MongoDB勉強会で発表を聞いてきたので、早速Shardingの機能を試してみます。
環境構成
まずは、以下の構成をします。
本当は複数台のサーバを使用したいのですが、手元に自由に扱えるサーバがさくらVPSしかないため
1台に複数のmongodを立て、mongosとconfigも同居させています。
mongodbのバージョンは、1.8.0を使用しています。
shardサーバ起動
mongodをポート別に3つ起動します。
[matsuou1@testsvr mongodb]$ ./bin/mongod --shardsvr --port 10001 --dbpath /tmp/mongodb/shard1 --logpath /tmp/mongodb/log/shard1.log & [1] 14269 [matsuou1@testsvr mongodb]$ ./bin/mongod --shardsvr --port 10002 --dbpath /tmp/mongodb/shard2 --logpath /tmp/mongodb/log/shard2.log & [2] 14276 [matsuou1@testsvr mongodb]$ ./bin/mongod --shardsvr --port 10003 --dbpath /tmp/mongodb/shard3 --logpath /tmp/mongodb/log/shard3.log & [3] 14287
configサーバ起動
[matsuou1@testsvr mongodb]$ ./bin/mongod --configsvr --port 10004 --dbpath /tmp/mongodb/config --logpath /tmp/mongodb/log/config.log & [4] 14296
mongosルータ起動
chunkの動作も見たいので、chunk sizeを1MBに設定し起動する。
[matsuou1@testsvr mongodb]$ ./bin/mongos --configdb localhost:10004 --port 10000 --logpath /tmp/mongodb/log/mongos.log --chunkSize 1 & [5] 14319
Shard構成
まずは、mongosのadminに接続し、Shardを追加する。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/admin MongoDB shell version: 1.8.0 connecting to: localhost:10000/admin > db admin > db.runCommand( { addshard : "localhost:10001" } ); { "shardAdded" : "shard0000", "ok" : 1 } > db.runCommand( { addshard : "localhost:10002" } ); { "shardAdded" : "shard0001", "ok" : 1 } > db.runCommand( { addshard : "localhost:10003" } ); { "shardAdded" : "shard0002", "ok" : 1 }
追加したshardが正しく追加されているかどうか、確認する。
> db.runCommand( { listshards : 1 } ); { "shards" : [ { "_id" : "shard0000", "host" : "localhost:10001" }, { "_id" : "shard0001", "host" : "localhost:10002" }, { "_id" : "shard0002", "host" : "localhost:10003" } ], "ok" : 1 } > db.printShardingStatus(); --- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:10001" } { "_id" : "shard0001", "host" : "localhost:10002" } { "_id" : "shard0002", "host" : "localhost:10003" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" }
テストデータ登録
使用するテストデータは、某サーバのアクセスログを使用しようかと思います。
年月、ユーザID、タイムスタンプ、URI、デバイスコードぐらいを投入してみます。
[matsuou1@testsvr mongodb]$ ./bin/mongoimport -h localhost:10000 -d logdb -c logs --ignoreBlanks --type tsv --fields month,uid,timestamp,path,device /tmp/mongodb/work/access_20100301.log connected to: localhost:10000 imported 28130 objects
sharding開始
ようやく環境の構成が完了したので、次はshardingの設定を行います。
コレクション単位でのshardingの開始
mongosに接続して、shardcollectionコマンドを発行する。今回のshard keyは勉強会で良い例として紹介されてたアクセスログの
年月とユーザIDの複合キーを採用。
いざ、shardcollectionコマンドを実行すると以下のエラーが。。。
> db.runCommand( { shardcollection : "logdb.logs" , key : { month : 1 , uid : 1 } } ); { "ok" : 0, "errmsg" : "sharding not enabled for db" }
エラーメッセージに従い、先にデータベース単位でのshardingしないとだめそうなので、先にenableshardingコマンドを実行する。
> db.runCommand( { enablesharding : "logdb" }); { "ok" : 1 } > db.runCommand( { shardcollection : "logdb.logs" , key : { month : 1 , uid : 1 } } ); { "ok" : 0, "errmsg" : "please create an index over the sharding key before sharding." }
今度はsharding keyに対して、sharding実施前にインデックスを作る必要があるとのこと。
chunkingプロセスの高速化のために必要であるとのことで、無ければ自動で作成しますと
マニュアルには記載されているが、どうも手動で作成する必要がありそう。
> use logdb switched to db logdb > db.logs.ensureIndex( { month : 1 , uid : 1 } ); > use admin switched to db admin > db.runCommand( { shardcollection : "logdb.logs" , key : { month : 1 , uid : 1 } } ); { "collectionsharded" : "logdb.logs", "ok" : 1 } > db.printShardingStatus(); --- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:10001" } { "_id" : "shard0001", "host" : "localhost:10002" } { "_id" : "shard0002", "host" : "localhost:10003" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "logdb", "partitioned" : true, "primary" : "shard0000" } logdb.logs chunks: shard0001 3 shard0002 2 shard0000 3 { "month" : { $minKey : 1 }, "uid" : { $minKey : 1 } } -->> { "month" : "2010/02", "uid" : "c2UGMAoXRXXXDgJ7" } on : shard0001 { "t" : 2000, "i" : 0 } { "month" : "2010/02", "uid" : "c2UGMAoXRXXXDgJ7" } -->> { "month" : "2010/03", "uid" : "a10StyXhoXXX2nb2" } on : shard0002 { "t" : 3000, "i" : 0 } { "month" : "2010/03", "uid" : "a10StyXhoXXX2nb2" } -->> { "month" : "2010/03", "uid" : "a34m3gIYWXXXH5xP" } on : shard0001 { "t" : 4000, "i" : 0 } { "month" : "2010/03", "uid" : "a34m3gIYWXXXH5xP" } -->> { "month" : "2010/03", "uid" : "b2EwnvdeFXXXoKO8" } on : shard0002 { "t" : 5000, "i" : 0 } { "month" : "2010/03", "uid" : "b2EwnvdeFXXXoKO8" } -->> { "month" : "2010/03", "uid" : "c23k2FVIiXXX86m3" } on : shard0001 { "t" : 6000, "i" : 0 } { "month" : "2010/03", "uid" : "c23k2FVIiXXX86m3" } -->> { "month" : "2010/03", "uid" : "d2GIFKklCXXXpoKq" } on : shard0000 { "t" : 6000, "i" : 1 } { "month" : "2010/03", "uid" : "d2GIFKklCXXXpoKq" } -->> { "month" : "2010/03", "uid" : "f3tMomXcKXXXwQMn" } on : shard0000 { "t" : 1000, "i" : 7 } { "month" : "2010/03", "uid" : "f3tMomXcKXXXwQMn" } -->> { "month" : { $maxKey : 1 }, "uid" : { $maxKey : 1 } } on : shard0000 { "t" : 1000, "i" : 8 }
printShardingStatusを見てみると、chunkが8個に分割され、shard000に3つ、shard001に3つ、shard002に2つ配置されている。
※ 使ったデータは小さめのログなので、デフォルトのchunk size(200MB)だと分割されないので、chunksizeを1Mに設定している。
※ 上記のuidは携帯のuidなので一部マスクを掛けています。
本当にshardingされているか確認
まずはmongosに接続し、全体logsコレクションの件数を確認する。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/logdb MongoDB shell version: 1.8.0 connecting to: localhost:10000/logdb > db.logs.count(); 28130
次に各shardでlogsコレクションの件数を確認する。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10001/logdb > db.logs.count(); 10296 [matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10002/logdb > db.logs.count(); 10696 [matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10003/logdb > db.logs.count(); 7138
各shardのlogsコレクションの件数を確認してみると、確かに分割され、件数もmongos経由した場合と同じ。
ドキュメントのサイズで分けているので、件数が同じにはならない。
データ追加
この状態でさらに7万件程データの追加を行って、chunkの偏りが発生しないかを確認してみる。
> db.printShardingStatus(); --- Sharding Status --- sharding version: { "_id" : 1, "version" : 3 } shards: { "_id" : "shard0000", "host" : "localhost:10001" } { "_id" : "shard0001", "host" : "localhost:10002" } { "_id" : "shard0002", "host" : "localhost:10003" } databases: { "_id" : "admin", "partitioned" : false, "primary" : "config" } { "_id" : "logdb", "partitioned" : true, "primary" : "shard0000" } logdb.logs chunks: shard0001 6 shard0002 6 shard0000 5 { "month" : { $minKey : 1 }, "uid" : { $minKey : 1 } } -->> { "month" : "2010/02", "uid" : "c2UGMAoXRXXXDgJ7" } on : shard0001 { "t" : 2000, "i" : 0 } { "month" : "2010/02", "uid" : "c2UGMAoXRXXXDgJ7" } -->> { "month" : "2010/03", "uid" : "a10StyXhoXXX2nb2" } on : shard0002 { "t" : 3000, "i" : 0 } { "month" : "2010/03", "uid" : "a10StyXhoXXX2nb2" } -->> { "month" : "2010/03", "uid" : "a2QsXVOrKXXXOsQf" } on : shard0001 { "t" : 6000, "i" : 2 } { "month" : "2010/03", "uid" : "a2QsXVOrKXXXOsQf" } -->> { "month" : "2010/03", "uid" : "a34m3gIYWXXXH5xP" } on : shard0001 { "t" : 6000, "i" : 3 } { "month" : "2010/03", "uid" : "a34m3gIYWXXXH5xP" } -->> { "month" : "2010/03", "uid" : "a3aDeqciNXXXwVSs" } on : shard0002 { "t" : 7000, "i" : 8 } { "month" : "2010/03", "uid" : "a3aDeqciNXXXwVSs" } -->> { "month" : "2010/03", "uid" : "b2EwnvdeFXXXoKO8" } on : shard0002 { "t" : 7000, "i" : 9 } { "month" : "2010/03", "uid" : "b2EwnvdeFXXXoKO8" } -->> { "month" : "2010/03", "uid" : "b2zjWlq3xXXXufa4" } on : shard0001 { "t" : 6000, "i" : 6 } { "month" : "2010/03", "uid" : "b2zjWlq3xXXXufa4" } -->> { "month" : "2010/03", "uid" : "b3vJ4e1bCXXXVHQS" } on : shard0001 { "t" : 7000, "i" : 10 } { "month" : "2010/03", "uid" : "b3vJ4e1bCXXXVHQS" } -->> { "month" : "2010/03", "uid" : "c23k2FVIiXXX86m3" } on : shard0001 { "t" : 7000, "i" : 11 } { "month" : "2010/03", "uid" : "c23k2FVIiXXX86m3" } -->> { "month" : "2010/03", "uid" : "c2egPLOFzXXXvHZd" } on : shard0002 { "t" : 7000, "i" : 2 } { "month" : "2010/03", "uid" : "c2egPLOFzXXXvHZd" } -->> { "month" : "2010/03", "uid" : "c3N2vMU8ZXXXsCmT" } on : shard0002 { "t" : 7000, "i" : 4 } { "month" : "2010/03", "uid" : "c3N2vMU8ZXXXsCmT" } -->> { "month" : "2010/03", "uid" : "d2GIFKklCXXXpoKq" } on : shard0002 { "t" : 7000, "i" : 5 } { "month" : "2010/03", "uid" : "d2GIFKklCXXXpoKq" } -->> { "month" : "2010/03", "uid" : "f10StyXdrXXX4mb2" } on : shard0000 { "t" : 7000, "i" : 1 } { "month" : "2010/03", "uid" : "f10StyXdrXXX4mb2" } -->> { "month" : "2010/03", "uid" : "f3tMomXcKXXXwQMn" } on : shard0000 { "t" : 6000, "i" : 5 } { "month" : "2010/03", "uid" : "f3tMomXcKXXXwQMn" } -->> { "month" : "2010/03", "uid" : "g2XA4wGX5XXXFjqn" } on : shard0000 { "t" : 7000, "i" : 6 } { "month" : "2010/03", "uid" : "g2XA4wGX5XXXFjqn" } -->> { "month" : "2010/03", "uid" : "i3zqETmH1XXXQeIX" } on : shard0000 { "t" : 7000, "i" : 7 } { "month" : "2010/03", "uid" : "i3zqETmH1XXXQeIX" } -->> { "month" : { $maxKey : 1 }, "uid" : { $maxKey : 1 } } on : shard0000 { "t" : 6000, "i" : 9 }
chunk数を見ると17個に分割され、shard0000に5つ、shard0001に6つ、shard0002に6つ配置されているのが分かり、shard間の差はほぼない。
一応、各shardの件数も確認してみる。
[matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10000/logdb > db.logs.count(); 96974 [matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10001/logdb > db.logs.count(); 28353 [matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10002/logdb > db.logs.count(); 33500 [matsuou1@testsvr mongodb]$ ./bin/mongo localhost:10003/logdb > db.logs.count(); 35121
件数についてもだいたい、均等に振られていることがわかる。
printShardingStatusで表示されるchunkの情報の最後の"t"と"i"は何の情報を示しているんだろうか?
ほんの少しだけ調べたけど分からなかったので、今度調べておくことにする。(分かる人がいたら教えてください><)
{ "month" : "2010/03", "uid" : "a34m3gIYWXXXH5xP" } -->> { "month" : "2010/03", "uid" : "a3aDeqciNXXXwVSs" } on : shard0002 { "t" : 7000, "i" : 8 }
まとめ
今回はmongodbのshardingの機能について、少しだけ使ってみました。
上記の通り、割と簡単に試せるので、やったことが無い人はやってみるとより理解が深まるかと思います。
次回以降は、shard keyを効率が悪いものに代えるとchunkの偏りがどのように発生するか、その場合に発生するMigrationの動作、failover時の動作、configサーバが落ちた場合の動作などを見ていけたらと考えています。
その前に、投入したアクセスログを集計してみるかもしれません。
第2回 MongoDB JP 勉強会に行ってきた
今週はMongoDBの勉強会に参加してきました。
Sharding詳解 [twitter:@doryokujin]
MongoDBでShardingを使用する際のポイントや注意点についての発表です。
こういう話はこれからShardingを使おうとする人にとっては大変有益。
前日にさくらVPSで試して見たので、割と理解できたような気がする。
- Shard Keyの設定は非常に重要、慎重に
- Shardの偏りを極力減らすことは重要
- Shard Keyによって偏り具合が大きく異なる
- 注意点
- Shard Keyは変更できない
- Shard Keyを持たないドキュメントは保存できない(nullは可能)
- Shard Key選択時の悪い例
- カーディナリティが低い値(性別等)
- Chunkの分割ができない
- カーディナリティがNならば、N個のChunkしかできない → N台以上のShardサーバは無意味
- 常に増加するデータ(Time、ObjectID、シーケンス等)
- Chunkの分割が常に同じ方向となるため、Shard間で不均一となる
- ランダムな値(ハッシュ値等)
- 非常に大きな範囲を持ったChunkが存在する可能性があり、Migration時にRAMを圧迫する
- indexが非効率
- カーディナリティが低い値(性別等)
- Shard Key選択時の良い例
- 緩く増加するキー + 検索でよく使われるキー
- アクセス解析{month:1 , user:1}
- monthは一定期間固定で、userは均等に分布される
- 時間がたつとmonthのキーの値が増え、古い値のChunkは分割されずMigrationが起こりにくい
- 緩く増加するキー + 検索でよく使われるキー
- Sharding環境でShard Keyを使用しないクエリは正しく実行されるとは限らない
- Chunk Migration中のcount
- Migration中は移動元、移動先に同じChunkが存在するため、重複してカウントする可能性がある
- 同時書き込み発生中のunique index
- 書き込みロックを行わないため、unique indexとして設定したキーが異なるShard間で存在する可能性がある(_idを含む)
- 同時書き込み発生中のsingle-update()
- Non Shard Keyに対し、同時にsingle-updateを実行するとエラーとなるため、multi-updateを実行
- tmp_collectionが削除されないmapreduce(v1.8で改善。手動で削除)
- tmp_collectionが自動で削除されないため、不要なcollectionが増えていく
- Chunk Migration中のcount
Type safe mongodb with Scala [twitter:@bibrost]
勝間Web 中の人の発表。
↓bibrostさんのブログで+αの話が。
第2回 MongoDB JP 勉強会+α アーキテクチャ選択の話
アクセスログをできるだけいろいろ見る時のmapreduce+ニフティクラウドでの構築とパフォーマンスを初心者からわかりやすく [twitter:@muddydixon]
資料は こちら から。
↓muddydixonさんのブログで解説があります。
第2回 MongoDB JP 勉強会 in Tokyoに参加してきました
地理空間インデックスを利用したWebアプリケーション [twitter:@yamaneko1212]
一部で話題沸騰の農家ニートプログラマことyamaneko1212さんによる発表。
資料は こちら から。(PDFです)
mongodbを使った地理空間インデックスのお話。
Tachy with MongoDB [twitter:@joe_hrmn]
サイバーエージェントの実名携帯SNSサイト「Tachy」でmongoDBを使用した際の話。
↓joe_hrmnさんのブログです。
第2回 MongoDB JP 勉強会に参加してきました
- ユーザ情報はMySQLで管理しているが、それ以外の情報は全てMongoDBで管理している。
- 採用理由
- picoで社内実績あり
- アクセスが高速
- 自動failover
- データ分散が自動
- 大量のinsertが遅いのでbulk insertにしたら早くなった
Toggeter [twitter:@ixixi]
所管&まとめ
- 全体的にログ解析等のバックエンドに使用されている感が強いが、「Tachy」でフロントエンドでも実用事例も出てきている。
- RDBMSみたいに誰でもなんとなく使えるものではないので、適用箇所、目的をはっきりする必要あり。
- 難しいのはcollectionやshard keyの設計。Embedした方が良いのか、しない方がよいのか、きちんと考えてから決めるべし。
さくらVPSにRStudioをインストールしてみた
昨日のR勉強会@東京でちょっとだけ話に出てきたRStudioのサーバ版をさくらVPSにインストールしてみました。
RStudioとは?
R言語のIDEです。デスクトップ版とサーバ版があります。
デスクトップ版は、Windowsだけでなく、Mac、Ubuntu、Fedoraもサポートしています。
サーバ版はUbuntuとCentOSはバイナリがあるので楽にインストールでき、サーバ版でもコードの補完が
出来るなど、ディスクトップ版と遜色ない感じで使えます。
Rのインストール
RStudioにはR自体は含まれていないので、まずはRのインストールから。
yumのリポジトリにはRがないので、CRANからインストール。
CRANのRはバージョンが2.10なので、RPMforgeやEPELを使ってください。
Windows、Linuxは2.11.1以上、Macは2.12が必須環境となります。
私の場合は、EPELを使ってたっぽいです。。。
リポジトリの追加は、RPMforge EPEL Remiリポジトリインストール辺りをご参照頂ければと。
riywoさん、ご指摘ありがとうございます!!
$ sudo yum install R
RStudioインストール
RPMからは以下の感じでさっくりインストールできます。
$ wget https://s3.amazonaws.com/rstudio-server/rstudio-server-0.92.44-x86_64.rpm $ sudo rpm -Uvh rstudio-server-0.92.44-x86_64.rpm
インストール後にサーバが起動します。
最新版はGitHubに公開されていますので、より人柱版を使いたい人はソースからインストールしてみると良いかと。
(若干、面倒くさそうなので私は見送りました・・・)
ポート設定
デフォルトのポートは、8787なので
http://<server-ip>:8787
でアクセスできますが、ポート閉じている場合はiptables等の設定をする必要があります。
使用ポートを代えたい場合は、設定ファイルでポートを指定する必要があります。
/etc/rstudio/rserver.conf
www-port=8787
設定後は、サーバを再起動します。
$ sudo rstudio-server stop $ sudo rstudio-server start
または
$ sudo rstudio-server restart
第12回R勉強会@東京に行ってきた
今回初めてR勉強会@東京に参加してきました。
結構前(1年ぐらい?)から開催されている勉強会に途中から参加、しかもRは素人とドキドキでしたが、楽しく勉強できました。
なにげに大森駅に降りたのも初めてだったような気もします。
Rで学ぶデータサイエンス 5パターン認識 1章 判別能力の評価 [twitter:@sleipnir002]
Rで学ぶ回帰分析と単位根検定 [twitter:@teramonagi]
単回帰分析を復習した後、単純に回帰分析を適用してはいけない『やってはいけないケース』を紹介。
そしてそれがなぜ起こるのかを実例を通して紹介した後、この問題を避けるための方法の1つという観点から単位根検定の紹介をします
- ランダムウォーク(=単位根過程)同士を回帰すると、あたかも関係がありそうに見える「見せかけの回帰」が発生する。
- 変数が単位根過程であるかどうかを検定する単位根検定をしよう
- Phillips-Perron検定や拡張Dickey-Fuller検定がよく使われるやり方
- 1に近いほど単位根過程である(0に近ければ単位根過程ではない)と判断できる
RをSQLで操る [twitter:@aad34210]
データベース(RDB)を利用している人でもRがとっつきやすくなる!
dataframeをSQLで操作ができる「sqldf」パッケージを紹介。
Rあんな時こんな時 〜いつか役立つ(かもしれない)Tips〜 [twitter:@sfchaos]
Rを使っていてこんなことをやりたいとき,こんなことに遭遇したとき,あなたはどうしますか?
クイズ形式で進行しながら,Rを使用する際のちょっとしたコツについて議論させていただければと思います
- NA/NaN/Infの判定(欠損値の発見)は、is.finite関数を使用する
- 「Rの基礎とプログラミ ング技法」は良い本なので、読みましょう
Togetter [twitter:@bob3bob3]
第1回 にこにこテキストマイニング勉強会に参加してきました。
テキストマイニングの勉強会に参加してきました。
非常に勉強になったので、復習の意味も込めて超久しぶりにブログを書きます。
この分野には前から興味はありましたが、なかなか勉強するきっかけがなかったので放置気味でしたが、折角の機会なので参加することに。
会場は勉強会の会場には定評があるOracleさんにて。
何気に初Oracleだったりしましたが、非常にすばらしい会場でしかも広い。
入館に若干時間がかかることが難点ですが、そこは仕方ないことでしょう。
目的&概要
目的
テキストマイニングについての学習のスタートアップ
テキストマイニング技術に関して気軽に参加・議論することができる場の提供
概要テキストマイニングとは、例えば製品の評判をweb上のテキストから抽出したり、
大量のアンケートテキストを分析するために用いられる技術であり、特にマーケティングの場で多くの利用例があります。この勉強会ではそうしたテキストマイニングを題材とし、用いられている要素技術とそれに関わる課題の議論、
第1回 にこにこテキストマイニング勉強会
またテキストマイニングを実務に活かす方法について考えていきます。
テキストマイニングの歩き方 [twitter:@AntiBayesian]
発表資料はここ(PDF)で公開されています。
テキストマイニングの利点
- ブログや掲示板など定型化されていないものを対象とするため、分析できるデータの範囲が大幅に拡大
- アンケートとは異なり想定外の回答が寄せられる可能性があり、収集者のフィルタがかかっていない生の声が得られる
- 性別・年代・地域などパーソナリティを8割ぐらい取得できる
- アンケートで個人情報を質問項目に入れると、回収率が極端に下がってしまう
言語処理の手法
テキストマイニングで使用するのは、1、2がほとんど。
テキストの統計処理
テキストマイニングの注意点
- テキストを数値化する際、必ず情報は欠損する
- テキストデータはスパース(疎)なデータである。疎なデータは通常の統計解析は通用しないケースが多い
- スパースデータ用の解析手法を用いる
- データ量を増やす
- 分析範囲を蜜な箇所だけに制限する
どの手法もそれぞれに問題があるが、まずは2を検討するべき(さらにスパースなデータが増加する可能性があるが。。)
実践するために
- 95%までは美しく実装できる@shuyo
- 400字詰め原稿用紙に20文字の誤字→使い物にならない
- 辞書を作り、クリーニングする
- 同義語辞書:私=私、俺、自分、僕、わたし
- ストップワード:(それ、あれ、私、君)
- 20人月の勝利
- 精度が単調に増加する。モデルを使用してやる場合は危険がある
ゆるふわテキストマイニングをしてみよう [twitter:@toilet_lunch]
発表資料はここ(PDF)で公開されています。
テキストマイニングとは
何をマイニングしたいかによって、扱うデータや手法が異なるため、一般的な定義が決められない。
評判分析のツール
精度をあげるには
- ジャンルを限定する
- テキストマイニングは通常、知りたい情報のジャンルをあらかじめ想定して行われる。
- 同じ評価表現がジャンルによって、反転を起こす場合がある
- 対象テキストのクリーニング
- 整理された形式で記述されていない
- つべこべいわず地道にクリーニングする
- 統計的な信頼性が損なわれるため、対象データが小さくなりすぎないように注意。
- 言語の困難さ
- 否定表現
- 未知語
- 助詞の省略
- 複合的表現
- 表記ゆれ
- 複数の評価の混在
- 複雑すぎる構造の文
考えだすときりがなく、人間でも解読できない文などがあるため、完全な対応は不可能。
要求される精度とリソースの兼ね合い
コピー&ペーストのみで始めるテキストマイニング超入門 [twitter:@langstat]
テキストマイニングの一般的な流れ
- データ構築
- テキスト収集、電子化
- テキスト処理
- 語彙表の作成、用例の抽出
- 統計処理
- 検定、多変量解析
- 質的分析
- 結果の解釈、実質科学的な考察
テキストを入手できるサイト
- 青空文庫
- 日本語のデータ
- Project Gutenberg
- 英語他のデータ
形態素解析ができるサイト
- テキスト解析デモ - 日本語形態素解析
- 出力形式を指定して、解析が可能
- Language Grid Playground (Morphological Analyzer)
統計解析できるサイト
初めてのnltk [twitter:@gepuro]
なんと大学2年生。
この分野に置ける先達がいる中で、初回発表する勇気がすばらしい。
アンケート自由回答のテキストマイニング事例 [twitter:@bob3bob3]
発表資料はここ(PDF)で公開されています。
商用テキストマイニングツール
- TRUE TELLER (野村総研)
- Text Mining Studio (数理システム)
- プリウス1台分ぐらいするらしい・・・が、おすすめ。
- SPSS Text Analysis for Survey (SPSS)
- ワードマイナー(日本電子)