rexml vs libxml-ruby

研究の関係で、37MBのXMLファイルに対して、XPathでデータを取り出したいという状況が起きました。

プロトタイプ実装として、Ruby標準ライブラリのrexmlでその処理プログラムを記述したのですが、
実行時にメモリを700MB以上消費しやがります途中で実行を中断したため、最大でメモリをどのくらい消費するかは不明
768MBしか積んでない私のマシンでは、メモリスワップが発生しまくりで実行が極端に重いため、
別の手段を考えることにしました。

手段としては2通り思いつきます。

  1. メモリ使用効率の良いXMLライブラリを使う
  2. SAXSimple API for XMLの略を使う

SAXで処理を実装するのはダルイので、今回は1番の手段にしました。

採用したXMLライブラリは、libxml-rubyっていうlibxmlのRuby Bindingです。
libxmlは、C言語で実装されたXMLライブラリで、libxml-rubyは、それをRubyで呼び出せるようにしたものです。

rexmlはRubyコードのみで実装されたXMLライブラリでして、libxml-rubyより実行速度が遅いですhttp://libxml.rubyforge.org/参照
きっと、メモリ使用効率もlibxml-rubyの方がいいだろうと期待して、採用しました。

rexmlはRuby1.8では標準で入ってますが、libxml-rubyは自分でインストールする必要があります。
インストールは、RubyGemsを使うと楽です。

私のCentOS 5環境下では以下の手順でインストールできました。

$ yum install libxml2-devel
$ yum install ruby-devel
$ gem install libxml-ruby

libxml-rubyを使って実装しなおしてみたところ、実行時の消費メモリは最大でも360MB程度になりました。
これなら、私のマシンで普通に実行できます。

XMLファイルサイズ、ライブラリ、メモリ消費量

DOM操作にしろXPathにしろ、DOM Treeを作るのに一番メモリを消費すると
思うんですが、実際、どの程度メモリを消費するのか気になったので、適当にググって見つけた
リンクを貼っときます。

FlashPlayer10で外部swfのロードに失敗する件

2008/10にFlashPlayer10が正式リリースされました。

Flashの動作に若干変更が加えられたようで、バイト先のWebサイトで今まで正常動作していたFlashがFlashPlayer10では動かないという問題が起きました。

挙動を調べてみると、MovieClipLoader.loadClipで外部swfのロードに失敗してます。

外部swfとして指定するURLは実際にはPHPファイルを指しており、GETパラメータを変えることで
PHPファイルが出力するswfデータが変わるようになってます。

どうも、PHPファイルがswfデータを出力する際に指定してるHTTPレスポンスヘッダが良くないようなので、調べてみるとContent-disposition 指定がswfロードに失敗する原因でした。

そこで、下記のようにContent-dispositionの指定をコメントアウトしたら、FlashPlayer10でも
外部swfのロードに成功しました。
[PHP]

[/PHP]

Content-dispositionの仕様はRFCで規定されています。その内容については、こちらによくまとめられています。
以下、一部引用

Content-Disposition レスポンスヘッダフィールドは、ユーザがその内容を
ファイルに保存したい場合にオリジンサーバが既定のファイル名を提案する事を
意味するように勧告されている。

Adobe的には、Flashでロードするswfコンテンツに、ファイルを保存する場合に指定するフィールドを指定するなってことなんでしょうかねえ。

その他FlashPlayer10の問題

FlashPlayer10になって、バージョン番号が1桁から2桁に増えたため、
バージョンチェックを適当に行うJavascriptを書いているサイトなどでは、
FlashPlayer10をFlashPlayer1と勘違いして、Flashが表示されない問題が起きてるようです。
http://bakera.jp/ebi/topic/3302

・・・なんとなく2000年問題を思い出しました。

追記

Adobe公式のFlashPlayer10におけるセキュリティ上の変更点解説の中で、
Content-Disposition: attachment 指定されたswfに対する挙動を変えた理由が書いてありました。

不特定の人がファイルをアップロード/ダウンロードできるアップローダサイト等で、
信頼できないユーザによってアップロードされたswfが、そのサイトドメイン上で実行される危険性を
なくすためだそうです。

画像やxmlファイルなどは、Content-Disposition: attachmentがHTMLレスポンスヘッダに
ついていても、今までと同様に動作するそうです。

PhpDocumentorによるドキュメント自動生成

バイト先のWebアプリケーション用ソースコードの量が増えてきたので、
そろそろドキュメント生成ツールでも使おうということで、そのメモ。

バイト先では、PHP & symfonyフレームワークで書いてるんで、
ドキュメント生成ツールにはPhpDocumentor現バージョンは1.4.2ですを使います。

インストールはPEARを使えば楽勝。

 $ pear install PhpDocumentor

で、ドキュンメントの生成にはphpdocコマンドを使います。

 $ phpdoc -d apps,lib -t doc/phpdoc

これで、appsとlibディレクトリ以下すべてのphpファイルをHTMLドキュメント化して、
doc/phpdoc以下に吐き出してくれます。

ただ、デフォルトで生成するHTMLには、charset=iso-8859-1が指定されているため、
日本語コメントは文字化けしてしまいます。

対処法としては、HTML内にcharset指定のないHTMLドキュメントを生成するのが楽ですとはいえ、webサーバのDefaultCharsetが間違っていたり、ブラウザの文字コード自動判定が失敗した場合は、文字化けが起きるので注意

 $ phpdoc -d apps,lib -t doc/phpdoc -o HTML:Smarty:PHP

この場合、デフォルトで生成したHTMLとはレイアウトが変わってしまいます。
デフォルトレイアウトが好きな方は、下記サイトを参考にテンプレートを書き換えてください。
http://je-pu-pu.jp/blog/archives/2006/04/phpdocumentor.html

参考文献

CentOSのyum追加パッケージ – RPMForge

CentOSのyumはFedora等に比べてyumでインストール可能なパッケージ数が少ないです。
そのため、インストールしようと思ったパッケージが存在しなくて困るときがあります。

この前は、inkscapeを入れようとしたけどパッケージが存在しなくて困りました。

ソースやrpmからインストールするには、いろんな依存パッケージをインストールする必要があって面倒です。

そこで、yumでインストール可能なパッケージを増やすために、RPMForgeを導入しました。
導入方法は、下記リンク先に書いてある通りです。

http://wiki.centos.org/AdditionalResources/Repositories/RPMForge

導入後は、以下のようにyumでインストールできました。

$ yum install inkscape

ActiveRecordの予約語とテーブルのカラム名

RubyのActiveRecordActiveRecordってデザインパターン名だったんだね。知らなかった・・・。http://ja.wikipedia.org/wiki/Active_Recordライブラリを使ってDB操作をした際、ハマッたのでメモ。

ActiveRecordを使うと、DBテーブルのレコードをオブジェクトとして取り出せます。
カラムのデータを取得する際は、カラム名をメソッド名としてオブジェクトを操作すれば良いのですが、
ActiveRecordの予約語と同じカラム名が存在すると正しく動作しません。

例えば、type, displayなどが予約語です。

ためしに、下記のようにテーブルとレコードをつくり、

$ mysql -u root test

CREATE TABLE apples
(
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    type VARCHAR(20) NOT NULL
);
INSERT INTO apples (type) VALUES ('fuji');

以下のRubyコードを書いたとします。
[Ruby]
require ‘rubygems’
require ‘activerecord’

ActiveRecord::Base.establish_connection(
:adapter => ‘mysql’,
:host => ‘127.0.0.1’,
:username => ‘root’,
:password => ”,
:database => ‘test’
)

class Apple < ActiveRecord::Base end a = Apple.find(1) p a.type [/Ruby] 上記コードを実行すると下記のような例外がでます。

/usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1434
:in `instantiate’: The single-table inheritance mechanism failed to locate 
the subclass: ‘fuji’. This error is raised because the column ‘type’ is reserved
for storing the class in case of inheritance. Please rename this column if you didn’t
intend it to be used for storing the inheritance class or overwrite 
Apple.inheritance_column to use another column for that information. 
(ActiveRecord::SubclassNotFound)

typeの場合は、上記のようにわかりやすい例外がでます。displayという名前のカラムが
ある場合は特に例外が発生しません。でも、a.displayと実行してもカラムのデータとは異なる値が
返ってくるので厄介です。

対処法としてはカラム名を変更(type -> etypeとか)するのが普通です。

カラム名を変更したくない場合はselectで別名を指定すれば、問題を回避できます。
[Ruby]
a = Apple.find(1, :select => ‘type as etype’)
p a.etype # “fuji”
[/Ruby]

ActiveRecordの予約語として何があるかは、下記リンクを見てください

その他参考文献

http://uruseiyatsura.way-nifty.com/blog/2007/08/ruby_on_rails.html

Perlの補完機能付きインタラクティブモード perlsh

前回の記事の続き。

今回はperl。

探してみると、やっぱり対話型インターフェイスを作ってる方がいますね。
メソッド名などの補完も行ってくれるものとして、perlshがありました。
perlshは、Term::ReadLine::Gnuライブラリに付属してます。

Term::ReadLine::Gnuのインストールには、cpanを使うと便利です。
普通にyum install perlとかしとけば、cpanコマンドも付いてくるっぽい。

ただ、私のCentOS 5.1だと、cpan経由のライブラリダウンロードURL (urllist)の
設定がされてなかったので、下記リンク先を参考にしてurllistを設定しました。
http://www.drk7.jp/MT/archives/000885.html

そして、Term::ReadLine::Gnuライブラリをインストールするわけなんですが、
事前にreadlineライブラリ等をyumなどを使ってインストールしとかないと、うまくインストールできないらしいですhttp://www.hasta-pronto.org/archives/2006/08/20-0408.php参照
私の環境では、すでにインストール済みだったので、特に問題ありませんでした。

Term::ReadLine::Gnuライブラリのインストールからperlshを使うまでの流れは以下、

$ cpan install Term::ReadLine::Gnu
$ perl ~/.cpan/build/Term-ReadLine-Gnu-1.17/eg/perlsh
main[1]$ use utf8
main[2]$ utf8:: [TAB]
utf8::             downgrade          is_utf8            unimport
AUTOLOAD           encode             native_to_unicode  upgrade
decode             import             unicode_to_native  valid
main[2]$ exit   #終了

perlshファイルは、実行パスの通ってるディレクトリに入れておくと起動が楽です。

PythonのインタラクティブモードでTab補完を使う

昨日の記事の続き

このまま、各言語のインタラクティブモードの補完機能について書いてけば、
しばらくネタに困らないので続けよう。

今回はPythonです。

pythonの場合、引数なしで起動すればインタラクティブモードになりますが、
下記のようにrlcompleterをimportすることで、補完機能が使えます。
ただし、readlineライブラリが必要です。Linuxとかなら、yum install pythonで普通に入るようです。
[Python]
$ python
>>> import rlcompleter
>>> rlcompleter.readline.parse_and_bind(‘tab: complete’)
>>> di [TAB]
dict dir divmod
>>> di
[/Python]

Windowsの人は、Python Alternative Readlineをインストールするのが楽だと思います。

若干、通常のreadlineと挙動が違うのがアレですが・・・。

参考サイト

Interactive ShellによるPHP対話入力補完

この前の記事の続き。

rubyには、irbっていうinteractive modeあります。
irb実行中に、 require ‘irb/completion’ すると、TABでメソッド名等の補完ができるようになって大変便利です。

PHPのinteractive modeでも同じことができないかなと思い、
探してみたところ、PHP5.1 から標準で導入されてることがわかりました補完機能付きのinteractive modeは、Interactive Shellっていう名称が付いてます。

ただし、–with-readline付きでPHPをコンパイルした場合に限ります。なんで、readlineを動的リンクするだけで使えるようにしてないんだー

yumでインストールしたPHPは、–with-readlineが付いてないので、少なくとも、CentOS 5.1のyumでインストールしたPHPは–with-readlineはついてませんでした。
PHP-cliだけソースコードからもう一度コンパイルしてみました。

環境は、CentOS 5.1です。

$ wget http://jp2.php.net/get/php-5.2.6.tar.gz/from/jp.php.net/mirror
$ tar xzvf php-5.2.6.tar.gz
$ cd php-5.2.6/
$ yum install libxml2-devel
$ yum install readline-devel
$ ./configure --prefix=~/local --disable-cgi --with-readline
$ make
$ make install
$ ~/local/bin/php -a
Interactive shell

php > get_class  [TAB]
get_class          get_class_methods  get_class_vars
php > get_class

うむ、便利だ。

万歩計の桁溢れを目指して歩く

この前、100円均一で万歩計を買いました。
99999歩までカウントできる万歩計です。

当然、10万歩を歩くと、万歩計の表示桁を溢れさせることができるんですが、
ふと、表示桁を溢れさせたら何か面白いことが起きるんじゃないかと思い立ち、
友人と一緒に10万歩を歩いてみました。

徒歩ルートは以下のようになりました。

  • 9月8日 14:20 横浜駅スタート
  • 大船駅まで根岸線沿いを歩く
  • 大船駅から江ノ島を目指して歩く
  • 江ノ島から、小田原まで海岸沿いを歩く
  • 9月9日 14:50 小田原駅近くで10万歩達成
  • その後は、交通機関をフルに使って箱根で適当に温泉に入って帰宅

途中、マックやデニーズで休憩をはさみましたが、大体1日あれば10万歩を歩くことができます。
後半は足が死にそうでした・・・。

結局、万歩系を桁溢れさせても、0歩になるだけで特に意味はありませんでしたw

約5000歩ごとに、携帯電話のGPSで位置を記録し、カメラで撮った写真と合わせて、
Google MapとKMLを使って徒歩経路を表示したのが下のマップになります(赤い線が徒歩経路)。


大きな地図で見る

GPS情報から総移動距離を求めたら約57kmでした。実際にはもう少し歩いた気がします。

Google Mapで経路表示を行ったのは初めてなんですが、GPX Editor JSなどを使うと、
比較的簡単に経路表示できました経路情報をGPX Editor JSへ入力する作業はめんどうでしたが