2006-06-06 [長年日記]
_ Zendネームスペースの下に入れるのはやめた
Zend_Search_HyperEstraierとして作りかけていたライブラリは、ひとまず単体のライブラリとしての完成度を高める方に集中するために、Zendネームスペース以下で構築するのは(他にやらなきゃならないことが増えるんで)いったんやめて、単にHyperEstraierネームスペース以下に構築することにした。いまいち使う気にならないLucene対抗にしようかと思ってたんだけど。
で、検索条件周りをいろいろいじっているうちに、HyperEstraier_SearchCondition::toQueryStringでノードAPIのパラメータになり、HyperEstraier_SearchCondition::to***(未定)Stringでestcmdのコマンドラインパラメータとなるのが妥当だよなーと思いつつ、そうなるとescmdのラッパーもないと意味がないよなーってことになり、そうなるといったいどこまで作ると一段落ってことになるのか先が見えなくなってきたのでした。
そういや検索条件をもっと設定しやすくしよう計画に関しては、一番わかりにくいのは属性検索の条件式表現だと思うんで、属性検索条件をセットする場合は、
$condition->addAttribute('@title', '==', 'foo');
$condition->addAttribute('@mtime', '>=', '2006/6/6');
とかやると、左辺値(既知のシステム属性の場合はそれにあわせる)や右辺値(左辺値から推測できなかった場合、右辺値が数値や日付として解釈できる場合はそれを優先する)から属性の種類を推測して、
$condition->attributes[] = '@title STREQ foo'; $condition->attributes[] = '@mtime NUMLE 2006/6/6';
とかに展開するようにしてみたんだけど、なんかいまいちすっきりしなくて中断中。どうせなら、
$condition->attributes[] = '@title == foo'; $condition->attributes[] = '@mtime >= 2006/6/6';
にしちゃった方がいいかなー。最悪でもセットされたパラメータをそのままHyper Estraierに渡せるようにしておけば、悪影響は出ないかな?
_ spycのパースって重いんだな
8kバイト+1kバイトのYAMLで書かれた設定ファイルをspycを使って 読み込むWebアプリ。当初の速度はこんな感じ。
Requests per second: 3.01 [#/sec] (mean) Time per request: 1662.891 [ms] (mean) Time per request: 332.578 [ms] (mean, across all concurrent requests)
ページ(データ取得+レンダリング)キャッシュをかましてみたんだけど、大して速くならなかった。
Requests per second: 3.67 [#/sec] (mean) Time per request: 1361.458 [ms] (mean) Time per request: 272.292 [ms] (mean, across all concurrent requests)
で、YAMLファイルの読み込みにキャッシュ(serializeして保存)をかましたら、劇的に速くなった。
Requests per second: 10.59 [#/sec] (mean) Time per request: 472.179 [ms] (mean) Time per request: 94.436 [ms] (mean, across all concurrent requests)
spycのパースってこんなに重い処理だったのか。
_ 配列が絡んだ__setの挙動
class Foo
{
protected $_array = array();
public function __get($name)
{
echo "__get called by $name\n";
switch ($name) {
case 'array': return $this->_array;
default:
throw new Exception();
}
}
public function __set($name, $value)
{
echo "__set called by $name, $value\n";
switch ($name) {
case 'array':
$this->_array = $value;
break;
default:
throw new Exception();
}
}
}
$foo = new Foo();
var_dump($foo->array);
$foo->array = array(1);
var_dump($foo->array);
$foo->array[] = 2;
var_dump($foo->array);
が、
__get called by array
array(0) {
}
__set called by array, Array
__get called by array
array(1) {
[0]=>
int(1)
}
__get called by array
__get called by array
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
ってなる(PHP 5.1.4/Windows XP Professional)のは正しいのか?
$foo->array[] = 2;
のところで__setが呼ばれずに、直接Foo::$_arrayに追加されているんだけど。
っつーか、
$foo->array[] = 2;
は
$tmp = $foo->array; array_push($tmp, 2); $foo->array = $tmp;
相当の処理だと信じていたんだけど。
_ serializeとvar_exportどちらが速いのか
Spycでパースしたデータを、serializeしてキャッシュするよりも、var_export($data, true)でPHPコードにしてキャッシュした方が速いんじゃね。と思ってベンチを取ってみた。
using Spyc::YAMLLoad start: 1149596540.0295 end: 1149596555.4353 elapsed: 15.405829191208 using serialize start: 1149596555.4358 end: 1149596555.64 elapsed: 0.2041699886322 using php var_export start: 1149596555.642 end: 1149596556.2202 elapsed: 0.57813310623169
あれー、PHPコードにするよりもserializeの方が速いのか。まあ確かにserializeの方が圧倒的にロジックが単純で済むしな。ただPHPコードとしてファイルに落としておけば、PHP Accelerator系のキャッシュが使えるだろうから、そういうのと組み合わせると速くなるかもしれない。けどまあ、ふつうはserializeを使おう。
一応コード
require_once 'spyc.php';
$yamlFile= 'spyc.yml';
echo "using Spyc::YAMLLoad\n";
$starttime = microtime(true);
for ($i = 0; $i < 1000; $i ++) {
$config = Spyc::YAMLLoad($yamlFile);
}
$endtime = microtime(true);
$elapsedtime = $endtime - $starttime;
echo "start: $starttime\n";
echo "end: $endtime\n";
echo "elapsed: $elapsedtime\n";
echo "\n";
echo "using serialize\n";
$serializedFile = 'spyc.yml.txt';
file_put_contents($serializedFile, serialize($config));
$starttime = microtime(true);
for ($i = 0; $i < 1000; $i ++) {
$config = unserialize(file_get_contents($serializedFile));
}
$endtime = microtime(true);
$elapsedtime = $endtime - $starttime;
echo "start: $starttime\n";
echo "end: $endtime\n";
echo "elapsed: $elapsedtime\n";
echo "\n";
echo "using php var_export\n";
$phpFile = 'spyc.yml.php';
file_put_contents($phpFile, '<?php return ' . var_export($config, true) . '?>');
$starttime = microtime(true);
for ($i = 0; $i < 1000; $i ++) {
$config = include $phpFile;
}
$endtime = microtime(true);
$elapsedtime = $endtime - $starttime;
echo "start: $starttime\n";
echo "end: $endtime\n";
echo "elapsed: $elapsedtime\n";
ishinaoさんによる__set挙動報告がありました。 思わず「ぉお?」と言い出しちゃいそうな返りが・・っ http://bugs.php.net/bug.php?id=36214 で報告されているらしいです。 #この挙動そのものを初めて知りました・・・ OS : WindowsXP PHP : 5.1.3-dev, 5.1.4



挙動から見ると
$tmp = $foo->array;
$tmp[] = 2;
相当の処理みたいですね。
ちなみに
$foo = new Foo();
$foo->array[] = 2;
var_dump($foo->array);
だと、__get が参照を返すか否かで挙動が変わります。
どうもバグっぽいですね。
$foo = new Foo();
$foo->array[] = 1;
var_dump($foo->array);
$foo->array[] = 2;
var_dump($foo->array);
$foo->array[] = 3;
var_dump($foo->array);
とやったら、
__get called by array
__get called by array
array(0) {
}
__get called by array
__get called by array
array(1) {
[0]=>
int(2)
}
__get called by array
__get called by array
array(2) {
[0]=>
int(2)
[1]=>
int(3)
}
という不思議な結果になりました。最初の1回だけ値返しで、2回目以降参照返しに変わる?
function &__getに変えて、明示的に参照返しするようにしたところ、
__get called by array
__get called by array
array(1) {
[0]=>
int(1)
}
__get called by array
__get called by array
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
__get called by array
__get called by array
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
と、理解可能な挙動になるんですけど。
どうやら
http://bugs.php.net/bug.php?id=36214
と同じ話っぽい。
ありゃ、(自分の書いた)ツッコミが一個消えた。tDiaryのバグか? 管理画面上は出てくるんだけど、勝手に非表示になったツッコミを、表示状態に戻せない。そろそろtDiaryもアップデートしどきか。
↑無理矢理tdcファイルをいじって表示させてみたけど、コメントを追加するとまたおかしくなりそうな予感。