Category Archives: 記録 - Page 4

Hadoop java.library.path 問題

今回はSWIGを利用してC++で書かれたプログラムをHadoop MapReduceから使おうとした。
これを参考にして以下のような処理を実行。

swig -c++ -java -package yayamamo -outdir yayamamo -noproxy hoge.i
g++ -fPIC -c HogeFuga.cpp
g++ -fPIC -c hoge_wrap.cxx -I/usr/local/java/include -I/usr/local/java/include/linux
g++ -shared HogeFuga.o hoge_wrap.o -o hoge.so

これに倣った実行テストプログラムはめでたく動作、かと思われたが、実はC++で書かれたそのサブルーチンは引数に文字列 (= char * ) を取り、それを直接書き換えるもので、javaから呼び出すとその引数である文字列は変化しない。javaのStringオブジェクトの中身を直接書き換えるようにはなっていないから。なので、C++側で、引数で与えられた文字列を変更した結果が戻り値となる新規ルーチンを用意。

続いて Hadoop で使うための環境を整える。ここを見るとどうやら mapred-site.xml で mapred.child.java.optsプロパティの値に -Djava.library.path=/home/mycompany/lib を加えるだけのように思われた。しかし、ここに設定するとジョブが失敗する。それまで正常に動作していたものも。Hadoop 本体を実行するするスクリプト内で設定している JAVA_LIBRARY_PATH と競合している模様。仕方ないので、Hadoop にバンドルされているネイティブコードライブラリの置かれるディレクトリ lib/native/Linux-amd64-64 以下に先ほど生成した hoge.so をコピー。問題無く動作することを確認。

OpenID Client on Perl

今回、TogoDoc で利用している OpenID のクライアントモジュールをNet::OpenID::Consumerから OpenID4Perl に変更。というよりは、追加という状況。Perlのコードそのものは何も変更せず。

さて、Consumer.pm は Crypt::DH を利用しており、DH.pm の冒頭には以下のコードがある。

use Math::BigInt lib => "GMP,Pari";

そして、TogoDoc では、Pari を利用しているため、Math::BigInt から Pari ライブラリを呼ぶ形になる。このため、Math::BigInt::Pari をインストールする。そうしないと、Crypt::DHを利用する際に、以下のような警告が出力される。

Math::BigInt: couldn't load specified math lib(s), fallback to Math::BigInt::FastCalc at .../local/lib/perl5/site_perl/5.10.1/Crypt/DH.pm line 6

また、Pari のスタックサイズの変更は最初にモジュールがロードされる前に宣言せねばならず、そしてmod_perl (2.0) 利用環境下でPariモジュールをロードするので、下記宣言を startup.pl に記述。

use Math::PariInit qw( stack=1e9 );

OpenID4Perl にすることで、一部のプロバイダのOpenIDでログイン出来なかった問題が解消された。

MySQL ストアドプロシージャ

mysql に保存されているデータベースに対して一気に特定の処理をする必要に迫られ、表記について学ぶ。
参考ページはhttp://dev.mysql.com/doc/refman/5.1/ja/stored-procedures.html
要はMySQLデータベースに保存可能な手続き、或いはプログラムということ。

もちろん、Perlなどから同じ処理は出来るが、頻繁に行うことでも無いし、何をしたのか良く分からなくなるプログラムが放置されるのも後で整理する時に困るので今回はこれを試してみた。

覚えておくと良い事項は、

  • デリミタを変更するコマンド DELIMITER を用いてプログラム内の1命令の終わりを示すセミコロンをMySQLコマンドの終わりとして解釈されないようにする。
  • プログラムの定義は “CREATE PROCEDURE プログラム() BEGIN” で開始、”END” で終了。
  • 変数宣言は “DECLARE”。
  • ある一定の条件を満たす行に対して、その内容を変更したい時、ストアドプロシージャではカーソル (CURSOR) という概念が使われる。
  • 条件を満たす行が複数あり、各行に同じ処理を施すならば、繰り返しを使うが、その終了条件は “SQLSTATE ‘0200’” 。
  • プログラムの保存先は、mysql.proc テーブル。

例えば、userinfo テーブルの RATE 列が 0 であるとき、それを 1 にしたい場合は以下のようなプログラムで実現可能。

DELIMITER $$
CREATE PROCEDURE myProc()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE r INT;
  DECLARE cur CURSOR FOR SELECT id FROM userinfo WHERE RATE=0;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; 

  OPEN cur;
  REPEAT FETCH cur INTO r;
    UPDATE userinfo SET RATE=1 WHERE id=r;
  UNTIL done END REPEAT;
  CLOSE cur;
END$$

“SELECT * FROM mysql.proc\G” というコマンドを発行すると実際に宣言したプログラムが保存されていることを確認出来る。
また、実行する場合は、CALL myProc;というコマンドを発行する。

CiteULike まとめ

http://www.citeulike.org/faq/data.adpに記述されているURLを利用してデータを取得。

誰(匿名)がいつ、何を投稿したのかが分かるデータ(Who-posted-what)と、各書誌情報についての情報が格納されているデータ(Article linkout data)を取得可能。
毎日更新している模様。

2009-08-30について調査。
Who-posted-what: 6 668 545行
一つの書誌情報について利用者が複数のタグを付けた場合は別々の行になるのでそこを吸収すると、
2 106 362行
のべ210万程度の書誌情報が投稿されていることになる。
更に、書誌情報についての重複を吸収すると、
1 783 077行
ということで、180万程度の書誌情報が投稿されていることになる。

また、利用者数は52 431人。一人当たりの平均登録件数は40件。
標準偏差が323もあるので、バラつきの大きいことが分かる。(最大は32 313…。続いて、30 695, 27 836, 27 825, 9 675…などと続く)
トップ1%を過ぎた時点での登録件数は600件。中央値は2(件)。したがって、半分以上の利用者が1, 2件しか登録していない。

因みに、最もCiteULike利用者の間で人気が高い論文は「The Structure of Collaborative Tagging Systems / Scott Golder, Bernardo A. Huberman / 2005」で、238人が投稿している。
CiteULikeのシステムに関連する話題のようで。
この分布もパワーローに従っているのでしょう。
それに続いて140人が登校しているのが、PMIDの付けられている、「Defrosting the digital library: bibliographic tools for the next generation web.」。
これまた、CiteULikeに関連する話題。
3番目は、「Conference on Hypertext and Hypermedia」。
その他、PMIDが付けられているところでは、「Collective dynamics of ‘small-world’ networks.」
ここの利用者の興味を反映した形ですね。

登録されているPMID付きの書誌情報は290 660なので、全体の16パーセント、1/6弱程度と少ない。
生命科学系の利用者は少数派なのだろう。
なお、15 192人が少なくとも一つのPMID付きの書誌情報を登録しており、これは全利用者の約3割にあたる。

hadoop取り敢えずまとめ

hadoop ver. 0.20.0 について

下記の項目に留意して効率アップをする

  • プログラム中でのconf.setNumReduceTasks(<INT>)の記述
  • プログラム中でのcombineの工夫
  • プログラム中でのconf.setCompressMapOutput(true);conf.setMapOutputCompressorClass(DefaultCodec.class);の記述
  • core-site.xmlでのio.sort.factorの設定(100など)

また、hdfsを使わない時の設定として留意する点は、core-site.xmlt中においてfs.default.nameをfile:///とすることとともに、mapred-site.xml中に、mapred.system.dirとmapred.temp.dirに対して、cluster環境下(=複数ノードに渡る構成)でも物理的に同一パスを指すようにする。

cluster環境下で、各ノードのローカルディスクが殆ど無いような環境では、/tmp下(=各ノードの物理ディスク領域)にそれぞれのノードで別々のnfsパスへのシンボリックリンクを張る。物理的に同じディスク領域が指定されるとディスクアクセスが適切に動作しない。

hadoop & eclipse

hadoopアプリの効率的な開発のためにeclipseを導入。
hadoop pluginがhadoopに梱包されているのでそれをeclipseのpluginフォルダにコピーする。

適切に初期設定をすると、eclipse内からhdfsが閲覧できたり、hadoopアプリを簡単にデバッグできるようになる。
とはいえ、hadoopバージョンアップに完全に追随できていない部分があるから、pluginの提供する機能の一部が使えない。

例えば、Project Explorerの、自分が実行させたいソースコードのファイル名の上で右クリックして「Run As」で表示される、「Run on Hadoop」は効かない。
今回はここを参考にしてみた。

因みに、hdfsを利用しないでhadoopのmap/reduceを走らせる時は、core-site.xml (0.20.0)かhadoop-site.xml (0.19.2)のfs.default.nameをfile:///とする。

NER を試す

ABNERはBioCreativeとNLPBA双方。
LingPipeはcmd_ne_en_bio_genia.shとcmd_ne_en_bio_genetag.sh双方。
更にLingPipeはここを参考にすべし。

RelEx 作業記録

CLASSPATH /home/yayamamo/src/opennlp-tools-1.4.3/output/opennlp-tools-1.4.3.jar:/home/yayamamo/src/opennlp-tools-1.4.3/lib/trove.jar:/home/yayamamo/src/opennlp-tools-1.4.3/lib/maxent-2.5.2.jar:/home/yayamamo/local/share/java/linkgrammar-4.5.8.jar:/home/yayamamo/src/jwnl14-rc2/jwnl.jar

[yayamamo@cl12 relex-1.1.0]$ ant
Buildfile: build.xml

build-subprojects:

init:

build-version:
[echo] Building RelEx version 1.1.0
[copy] Copying 1 file to /mnt/auto/home/yayamamo/src/relex-1.1.0/src/java/relex

look-for-gate:
[echo] Will not build GATE-based entity detector; GATE classes not found.

look-for-owl:
[echo] Will not build OWL output format; org.semanticweb.owl classes not found.

look-for-opennlp:

build-project:
[echo] relex: /mnt/auto/home/yayamamo/src/relex-1.1.0/build.xml
[javac] Compiling 134 source files to /mnt/auto/home/yayamamo/src/relex-1.1.0/bin
[javac] /mnt/auto/home/yayamamo/src/relex-1.1.0/src/java/relex/parser/RemoteLGParser.java:31: シンボルを見つけられません。
[javac] シンボル: クラス LGRemoteClient
[javac] 場所 : relex.parser.RemoteLGParser の クラス
[javac] private LGRemoteClient linkGrammarClient = new LGRemoteClient();
[javac] ^
[javac] /mnt/auto/home/yayamamo/src/relex-1.1.0/src/java/relex/parser/RemoteLGParser.java:179: シンボルを見つけられません。
[javac] シンボル: クラス LGRemoteClient
[javac] 場所 : relex.parser.RemoteLGParser の クラス
[javac] public LGRemoteClient getLinkGrammarClient()
[javac] ^
[javac] /mnt/auto/home/yayamamo/src/relex-1.1.0/src/java/relex/parser/RemoteLGParser.java:184: シンボルを見つけられません。
[javac] シンボル: クラス LGRemoteClient
[javac] 場所 : relex.parser.RemoteLGParser の クラス
[javac] public void setLinkGrammarClient(LGRemoteClient linkGrammarClient)
[javac] ^
[javac] /mnt/auto/home/yayamamo/src/relex-1.1.0/src/java/relex/parser/RemoteLGParser.java:31: シンボルを見つけられません。
[javac] シンボル: クラス LGRemoteClient
[javac] 場所 : relex.parser.RemoteLGParser の クラス
[javac] private LGRemoteClient linkGrammarClient = new LGRemoteClient();
[javac] ^
[javac] 注:一部の入力ファイルは推奨されない API を使用またはオーバーライドしています。
[javac] 注:詳細については、-Xlint:deprecation オプションを指定して再コンパイルしてください。
[javac] エラー 4 個

BUILD FAILED
/mnt/auto/home/yayamamo/src/relex-1.1.0/build.xml:96: Compile failed; see the compiler error output for details.

Total time: 2 seconds

参考にすべきページ

Hadoop io.compress / distributive

Version 0.20.0 (java 1.6.0_13 on SunOS 5.10)の話。
Mapの出力を圧縮するのにGzipCodecを利用したら何故か動作せず。
BZip2CodecならOK。
と思ったら、こちらもダメ。(コンパイルは通るのだが、実際に実行すると途中でコケる)
DefaultCodec でようやく問題無く動作。
まだ色々難しいのだろうか。

distributiveなMap関数の場合はCombinerを使う。

追記
どうやらSunOS 5.10/sparcだから問題があるようだ。
Java で Sun だから、むしろこちらの方が望ましいかと思いきや。
util.NativeCodeLoader で Loaded the native-hadoop library と表示されるのは x86 で、sparcマシンでは失敗する。

追記2
Reduce Taskの数を複数にするためには conf/mapred-site.xml に mapred.tasktracker.reduce.tasks.maximum の数を大きくするだけではなく、実際のソースコードに conf.setNumReduceTasks(30) の様に設定する必要がある。