MongoDBの配列をpop&push

MongoDBにて、embeddedのpushとpop操作をしてみました。キューのように扱いたいわけです。

# 配列を追加します
> db.test.insert({"digits":["one","two","three"]})

# 追加されているか確認します
> db.test.find();
{ "_id" : ObjectId("51146fb83ea7b17c770fac3a"), "digits" : [ "one", "two", "three" ] }

# $popを使って、左端をpopします。1を指定すると右端がpopされます。
> db.test.update({"_id":ObjectId("51146fb83ea7b17c770fac3a")}, { $pop: {"digits" : -1}})

# "one"が取り除かれました。
> db.test.find();
{ "_id" : ObjectId("51146fb83ea7b17c770fac3a"), "digits" : [ "two", "three" ] }

# $pushを使ってみます。これは配列の一番最後にappendされるようです。
> db.test.update({"_id":ObjectId("51146fb83ea7b17c770fac3a")}, { $push: {"digits" : "four"}})

# きちんと追加されました。
> db.test.find();
{ "_id" : ObjectId("51146fb83ea7b17c770fac3a"), "digits" : [ "two", "three", "four" ] }

Redisでのpopの場合返り値はpopしたものになるのですが、MongoDBだと何も返ってこないようですね。popするものを取り出したければ、その前に$sliceして取り出す必要がありそうです。

———-
追記@2013年2月11日

FindAndModifyという操作があるようです。findしてから何かの操作が出来るようです。ですから、FindAndModifyを使って、findしてからpopすれば、popするものを取り出せますね。
———-

MongoDBにて、複数のキー(配列)で検索するクエリ

MySQLなどでは、たとえばprimary keyが100, 1243, 1444のものを引っ張ってきたいときには、select * from example_table where id in (100, 1243, 1444); などとすると思います。MongoDBではどうするのかと思っていました。

MongoDBでは、$in を使えば一回のクエリで行けるみたいです。↓こんな感じです。

> db.user.find({"_id":  {$in : [ObjectId("5112a6626d33d30914000250"), ObjectId("5112a6626d33d3091400024e")]}  });

当たり前と言えば当たり前ですが、忘れるので自分用に書いておきます^^;

PHP付属のハッシュ化関数を全部試す+パフォーマンスの確認(ついでにSHA-3も)

PHPではhash_algos()というメソッドを使うと、用意されているハッシュ化関数名一覧が出ます。それをhash()メソッドに入れてみて、さらに1000000回実行してパフォーマンス計測してみました。

結論としては、md2はやたらと遅い(変なバイナリなのではと思います。誰も使わないから古いものがそのまま残っている感)、SHA-3(keccak)も少々遅い(とは言えそれと同じぐらい遅いものもいくつもある上に、最近メジャーになってきたので最適化がまだまだかと)、といったところでしょうか。とは言え100万回計算してもどれも10秒以内ですから、かなり高速に感じます。特筆すべき点は特にないように思います。いわゆる暗号学的ハッシュ関数にもいろいろあるのですね。何を使えばいいのか悩むところですが、ひとまずSHA-3なのですかねぇ。とは言え出力の文字列が長いの気になるところ。。。ちなみにPHP5.4と5.3のアルゴリズムの種類を見ると、お互い異なるものが存在しますね。

それと相変わらずMacBookがトロイのはどういうことなのでしょう。。。

SHA-3のPHPでの動かし方は手前味噌ですがこちらを参考にしてください -> http://mitsuakikawamorita.com/blog/?p=1018

ソース

<?php

$moji = 'algos performance';
foreach (hash_algos() as $hash_name) {
	$hash = hash($hash_name, $moji);
	printf("%10s: %s\n", $hash_name, $hash);
}
printf("%10s: %s\n", 'keccak', bin2hex(keccak_hash($moji)));

$n = 1000000;
printf("\n**** Performance(N = %s) *****\n", $n);

// Hash Alogs
foreach (hash_algos() as $hash_name) {
	$hash = 'performance';
	$start = microtime(true);
	for ($i = 0; $i < $n; $i++) {
		$hash = hash($hash_name, $hash);
	}
	$end = microtime(true);
	printf("%10s: %.5f [sec]\n", $hash_name, (double) ($end - $start));
}

// SHA-3
$hash = 'performance';
$start = microtime(true);
for ($i = 0; $i < $n; $i++) {
	$hash = bin2hex(keccak_hash($hash));
}
$end = microtime(true);
printf("%10s: %.5f [sec]\n", 'keccak', (double) ($end - $start));
?>


実行結果その1
– MacBook late2009(core2duo, 4GBDRAM, Mac OS 10.6 Snow Leopard)
$ php -v
PHP 5.4.10 (cli) (built: Dec 20 2012 19:20:33) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
    with Xdebug v2.2.1, Copyright (c) 2002-2012, by Derick Rethans

$ php sandbox.php 
       md2: dc5fdf95304b291ad10964a7ccb7faa5
       md4: 801db403e0ac9255f113ff8266359070
       md5: 6c2dfed571864558f3b8ea9738923863
      sha1: 1d45258a72773b3fdf034fcc679b96c27b3c40fe
    sha224: a9e6a29d3a4d948f8a35a3cdd9af615ada94b5614a35af6dbdfb5651
    sha256: 26819e9bc3af4062ebd53e4765693d5597cba5686f7be88b1e36850e855579d2
    sha384: d3b9e384a00fcae28b9fc79b15756e0c61d28b8f6857d7e7922f682beaa8316a48a9db7341bf6f25bf52acbc6fec230d
    sha512: f5fcff252ad88f1864204a7e133e23bde349db0b436d56831a93579f89524bde272e9d6497c97c378919158400b9ec4a22066afad30b80f00d96a1d6d5b3fc86
 ripemd128: 67a64c4f4f0b9cb10c43ca14ebe18117
 ripemd160: 8f51ad428aed52a46a06557d82635747623a2c9c
 ripemd256: dffc45861872b5ce5c089aed361c6607919e6f276cbc7bb8fce3d9cb98fc11e1
 ripemd320: 1de909a692518d934c41f51c242141975adcd0e38d5e638cb8f83e2d227caf79770af177defbe226
 whirlpool: 1a8d9459ab523580f0379a22f9a50d2b66de081e6af95e2163cbdb2492c2e58b4eb2e53f767780e27a3dcd67dd7594c15f55e9f33f91ea7f19791b4a5483a22a
tiger128,3: f667f64252472058ad1dea3c97dc3e8d
tiger160,3: f667f64252472058ad1dea3c97dc3e8d7e8f2178
tiger192,3: f667f64252472058ad1dea3c97dc3e8d7e8f21783b160c28
tiger128,4: 2db0838338baa8dc6e4c3ce1bcc7fac1
tiger160,4: 2db0838338baa8dc6e4c3ce1bcc7fac15353cac6
tiger192,4: 2db0838338baa8dc6e4c3ce1bcc7fac15353cac67187f141
    snefru: c81ee5f5381c7a9709f7709e0bc63d1cd5b4333d37b3389378fea1265e55776a
 snefru256: c81ee5f5381c7a9709f7709e0bc63d1cd5b4333d37b3389378fea1265e55776a
      gost: e1842374d66056297a2cb03b840e23b7c3f4422357b2178b240123d53ba053b5
   adler32: 3c7706c9
     crc32: 3201660f
    crc32b: 56e6ae46
    fnv132: 4453803d
    fnv164: 6bef313bb7589bbd
     joaat: 5552c25f
haval128,3: 9721431b6537e74c26cb1536c7be41d4
haval160,3: 342391bcbef50aeecc8521df99fd1e284f55bc85
haval192,3: 11e501c4e54c9bf606138923ed431cd8c35547f4badb7385
haval224,3: ef5e82e4f691fa66c6f8417a957afc38fab552c311b22ddd185532b0
haval256,3: 192afeb02f7029738ca2189b893a59f326c1e72a7b6265822ab0b14ae64a96e4
haval128,4: 114ec8f8dfca56d3d2b85978f1628cf8
haval160,4: b6ff22a049f93ae83aef8969f35b3488b49dfced
haval192,4: 2e3f8aa402af29ae32d8a3d0e2639395a028bf0f9de47cdc
haval224,4: b77725701eedf9b21f8c13ba9445b5e5981cac84bc037797bb8f1308
haval256,4: 4334dab741b985593327837bad9f271776a69a852e02aa7b7fca491a99220df0
haval128,5: 29fdb57b4b47e040f02f42f9fe65bc16
haval160,5: f6a3d75425772e104a01a7b90d83013ec5deecb5
haval192,5: 7ebfe513d9d3fcbca3fb90f3549453ba2ad608cf43f781df
haval224,5: 03296d01560715739b2e159d3ae6b814c6830e94da66114ad1e8b6a8
haval256,5: 153d045c9fcb0a693584b27c05ffd7febbfd798b4c7d551c72c4c995855ade97
    keccak: c0c6452f07c5f35f02aca35a6d17807aab9f6ca0a0016c13b2290fa46f5c86e0b64c8d4c60b11a0b4f3d758b4100fb79b3fbdaf34576bed1201dc574ae958658

**** Performance(N = 1000000) *****
       md2: 10.48892 [sec]
       md4: 2.23778 [sec]
       md5: 2.19680 [sec]
      sha1: 2.48040 [sec]
    sha224: 3.81560 [sec]
    sha256: 3.83991 [sec]
    sha384: 3.21141 [sec]
    sha512: 4.39060 [sec]
 ripemd128: 2.71953 [sec]
 ripemd160: 2.88354 [sec]
 ripemd256: 3.27086 [sec]
 ripemd320: 3.88254 [sec]
 whirlpool: 7.04390 [sec]
tiger128,3: 2.54103 [sec]
tiger160,3: 2.61623 [sec]
tiger192,3: 2.58919 [sec]
tiger128,4: 2.75476 [sec]
tiger160,4: 2.80707 [sec]
tiger192,4: 2.79212 [sec]
    snefru: 8.44477 [sec]
 snefru256: 8.48887 [sec]
      gost: 6.15553 [sec]
   adler32: 1.88503 [sec]
     crc32: 1.89609 [sec]
    crc32b: 1.89282 [sec]
    fnv132: 1.87824 [sec]
    fnv164: 1.92032 [sec]
     joaat: 1.90708 [sec]
haval128,3: 3.35714 [sec]
haval160,3: 3.43854 [sec]
haval192,3: 3.38524 [sec]
haval224,3: 3.37452 [sec]
haval256,3: 3.46517 [sec]
haval128,4: 3.78612 [sec]
haval160,4: 3.84510 [sec]
haval192,4: 3.80863 [sec]
haval224,4: 3.80868 [sec]
haval256,4: 3.89793 [sec]
haval128,5: 4.13596 [sec]
haval160,5: 4.24811 [sec]
haval192,5: 4.48140 [sec]
haval224,5: 4.27720 [sec]
haval256,5: 4.25700 [sec]
    keccak: 8.86619 [sec]


実行結果その2(とあるVM)
– CPU 2cores (Intel(R)Xeon(R) CPU X5650 @ 2.67GHz)
– 4GBDRAM (“dd if=/dev/zero of=/dev/null bs=1024K count=100000″ したら、11.3 GB/s でした)
# php -v
PHP 5.3.3 (cli) (built: Jul  3 2012 16:53:21) 
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

# php deleteok.php 
       md2: dc5fdf95304b291ad10964a7ccb7faa5
       md4: 801db403e0ac9255f113ff8266359070
       md5: 6c2dfed571864558f3b8ea9738923863
      sha1: 1d45258a72773b3fdf034fcc679b96c27b3c40fe
    sha224: a9e6a29d3a4d948f8a35a3cdd9af615ada94b5614a35af6dbdfb5651
    sha256: 26819e9bc3af4062ebd53e4765693d5597cba5686f7be88b1e36850e855579d2
    sha384: d3b9e384a00fcae28b9fc79b15756e0c61d28b8f6857d7e7922f682beaa8316a48a9db7341bf6f25bf52acbc6fec230d
    sha512: f5fcff252ad88f1864204a7e133e23bde349db0b436d56831a93579f89524bde272e9d6497c97c378919158400b9ec4a22066afad30b80f00d96a1d6d5b3fc86
 ripemd128: 67a64c4f4f0b9cb10c43ca14ebe18117
 ripemd160: 8f51ad428aed52a46a06557d82635747623a2c9c
 ripemd256: dffc45861872b5ce5c089aed361c6607919e6f276cbc7bb8fce3d9cb98fc11e1
 ripemd320: 1de909a692518d934c41f51c242141975adcd0e38d5e638cb8f83e2d227caf79770af177defbe226
 whirlpool: 1a8d9459ab523580f0379a22f9a50d2b66de081e6af95e2163cbdb2492c2e58b4eb2e53f767780e27a3dcd67dd7594c15f55e9f33f91ea7f19791b4a5483a22a
tiger128,3: 5820475242f667f68d3edc973cea1dad
tiger160,3: 5820475242f667f68d3edc973cea1dad280c163b
tiger192,3: 5820475242f667f68d3edc973cea1dad280c163b78218f7e
tiger128,4: dca8ba388383b02dc1fac7bce13c4c6e
tiger160,4: dca8ba388383b02dc1fac7bce13c4c6e41f18771
tiger192,4: dca8ba388383b02dc1fac7bce13c4c6e41f18771c6ca5353
    snefru: c81ee5f5381c7a9709f7709e0bc63d1cd5b4333d37b3389378fea1265e55776a
 snefru256: c81ee5f5381c7a9709f7709e0bc63d1cd5b4333d37b3389378fea1265e55776a
      gost: e1842374d66056297a2cb03b840e23b7c3f4422357b2178b240123d53ba053b5
   adler32: 3c7706c9
     crc32: 3201660f
    crc32b: 56e6ae46
   salsa10: e0224add29548ef6c8228362524282bc42dbbb4db3018c52144ec218907372830f8712d5d4d30fd2ca63c25f47cbb4f4d5460c3eff65e466488ab57798d63070
   salsa20: 7995d7b43ecae043671c03f866b05bf751d494d652c1a2eee0e119ff8e400ab862b61c14dceabbbb7097f3a98fe61c97cbff05c3aff2581aafa9bf6bdd39c314
haval128,3: 9721431b6537e74c26cb1536c7be41d4
haval160,3: 342391bcbef50aeecc8521df99fd1e284f55bc85
haval192,3: 11e501c4e54c9bf606138923ed431cd8c35547f4badb7385
haval224,3: ef5e82e4f691fa66c6f8417a957afc38fab552c311b22ddd185532b0
haval256,3: 192afeb02f7029738ca2189b893a59f326c1e72a7b6265822ab0b14ae64a96e4
haval128,4: 114ec8f8dfca56d3d2b85978f1628cf8
haval160,4: b6ff22a049f93ae83aef8969f35b3488b49dfced
haval192,4: 2e3f8aa402af29ae32d8a3d0e2639395a028bf0f9de47cdc
haval224,4: b77725701eedf9b21f8c13ba9445b5e5981cac84bc037797bb8f1308
haval256,4: 4334dab741b985593327837bad9f271776a69a852e02aa7b7fca491a99220df0
haval128,5: 29fdb57b4b47e040f02f42f9fe65bc16
haval160,5: f6a3d75425772e104a01a7b90d83013ec5deecb5
haval192,5: 7ebfe513d9d3fcbca3fb90f3549453ba2ad608cf43f781df
haval224,5: 03296d01560715739b2e159d3ae6b814c6830e94da66114ad1e8b6a8
haval256,5: 153d045c9fcb0a693584b27c05ffd7febbfd798b4c7d551c72c4c995855ade97
    keccak: c0c6452f07c5f35f02aca35a6d17807aab9f6ca0a0016c13b2290fa46f5c86e0b64c8d4c60b11a0b4f3d758b4100fb79b3fbdaf34576bed1201dc574ae958658

**** Performance(N = 1000000) *****
       md2: 7.40731 [sec]
       md4: 0.44793 [sec]
       md5: 0.47436 [sec]
      sha1: 0.62465 [sec]
    sha224: 1.52405 [sec]
    sha256: 1.51239 [sec]
    sha384: 1.16941 [sec]
    sha512: 1.91125 [sec]
 ripemd128: 0.72216 [sec]
 ripemd160: 0.88384 [sec]
 ripemd256: 1.17934 [sec]
 ripemd320: 1.54348 [sec]
 whirlpool: 3.62870 [sec]
tiger128,3: 0.56910 [sec]
tiger160,3: 0.56558 [sec]
tiger192,3: 0.57787 [sec]
tiger128,4: 0.66020 [sec]
tiger160,4: 0.70116 [sec]
tiger192,4: 0.69095 [sec]
    snefru: 4.91457 [sec]
 snefru256: 4.27670 [sec]
      gost: 3.19095 [sec]
   adler32: 0.34289 [sec]
     crc32: 0.31718 [sec]
    crc32b: 0.31691 [sec]
   salsa10: 0.91331 [sec]
   salsa20: 0.86919 [sec]
haval128,3: 1.15367 [sec]
haval160,3: 1.16505 [sec]
haval192,3: 1.16742 [sec]
haval224,3: 1.17457 [sec]
haval256,3: 1.17772 [sec]
haval128,4: 1.46374 [sec]
haval160,4: 1.46836 [sec]
haval192,4: 1.54590 [sec]
haval224,4: 1.48484 [sec]
haval256,4: 1.49092 [sec]
haval128,5: 1.71193 [sec]
haval160,5: 1.72039 [sec]
haval192,5: 1.73949 [sec]
haval224,5: 1.73865 [sec]
haval256,5: 1.73673 [sec]
    keccak: 2.08019 [sec]

MongoDBにてembeddedを指定件数だけ取得

MongoDBのコレクションに入れた配列の一部を取り出したいと思いました。Pagingのようなことをしたいわけです。いろいろと探した結果、$sliceというものを用いれば良いようです。

では具体例を。。。MongoDBのシェルでの操作で示します。

# 配列を含んだドキュメントをinsert
> db.test.insert({"paging":"available", "elements":["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]})

# きちんとinsertされたかどうか確認するため全件表示してみる
> db.test.find();
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ 	"one", 	"two", 	"three", 	"four", 	"five", 	"six", 	"seven", 	"eight", 	"nine", 	"ten" ] }

# $slice というものを用いて初めの3件だけ取得
> db.test.find({"_id":ObjectId("510cf16444ebf951ba5f7b2c")}, {"elements":{$slice:3}});
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ "one", "two", "three" ] }

# $sliceにマイナスを指定すると、後ろからという意味です。Pythonのリストみたいな感じですね。
> db.test.find({"_id":ObjectId("510cf16444ebf951ba5f7b2c")}, {"elements":{$slice:-2}});
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ "nine", "ten" ] }

# 0番目から5個の要素を取得、のようなことも指定できます。
> db.test.find({"_id":ObjectId("510cf16444ebf951ba5f7b2c")}, {"elements":{$slice:[0, 5]}});
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ "one", "two", "three", "four", "five" ] }

# 3番目から5個取ってくる
> db.test.find({"_id":ObjectId("510cf16444ebf951ba5f7b2c")}, {"elements":{$slice:[3, 5]}});
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ "four", "five", "six", "seven", "eight" ] }

# 後ろから2番目から5個取ってくる(要素が10個しかないので、このようなクエリだと該当は2個だけですが)
> db.test.find({"_id":ObjectId("510cf16444ebf951ba5f7b2c")}, {"elements":{$slice:[-2, 5]}});
{ "_id" : ObjectId("510cf16444ebf951ba5f7b2c"), "paging" : "available", "elements" : [ "nine", "ten" ] }

というわけでした。