今どき perl 開発環境を調べてみた

この記事はずいぶん古いです。

来てくださった方、大変申し訳ない!
新しいの書いてます。m(_ _)m

-cpanm の説明。前までは PERL5LIB とか環境変数周りをグリグリして汚染が原因でハマる事も。とっても便利です。

あと個人的に一番知りたいのは、cpan モジュールの管理方法。
昔、分散するサーバ全てを全く同じ構成でコピー作成し、そのうち1台だけに cpan モジュールをいれて、そのディレクトリを nfs で他サーバが参照するという、乱暴な方法で管理していた。メモリにロード出来てパスさえ通ってればいいかな?と...

ほんとはみんなどうしてるんだろう?

perl で画像処理

ちょっとゴニョゴニョした画像処理をやることになりました。

perl でさらっと出来ないかと思いましたが...

GD
Image::Magick
Imager


正直、アタクシのレベルでは「どれがいいのー!?」

という感じです。

とは言うものの、悩んでいてもしかたないので
まずはベンチです。ベンチ。

要件

 * JPEG 
 * 600px * 800px
 * 48.37 KB

を とりあず端から端までラスタスキャンしてRGB値を取得する。

これを 10 回繰り返す。

環境

cpu:Intel(R) Core(TM)2 Quad CPU Q9400 @ 2.66GHz
mem:3G
os: CentOS 5.2(32bit)


すると以下のような結果に...

Benchmark: timing 10 iterations of GD, IMAGER, MAGICK...
        GD: 16 wallclock secs (16.58 usr +  0.03 sys = 16.61 CPU) @  0.60/s (n=10)
    IMAGER: 57 wallclock secs (56.42 usr +  0.01 sys = 56.43 CPU) @  0.18/s (n=10)
    MAGICK: 11 wallclock secs (11.11 usr +  0.10 sys = 11.21 CPU) @  0.89/s (n=10)
       s/iter IMAGER     GD MAGICK
IMAGER   5.64     --   -71%   -80%
GD       1.66   240%     --   -33%
MAGICK   1.12   403%    48%     --


うーん。こんなに差があった。

って事で今回はperlでやるならImage::Magick を採用。

スクリプト

#!/usr/bin/env perl

use strict;
use warnings;

use Benchmark qw(timethese  cmpthese);
use GD;
use Image::Magick;
use Imager;

=head
/*
 * [ 今回の画像スペック ]
 * JPEG 
 * 600px * 800px
 * 48.37 KB
 *
 */
=cut
use constant ImageFile => 'target.jpg';
use constant Count     => 10;

my $comp = timethese(
    Count,
    {
      GD     => \&_f1,
      MAGICK => \&_f2,
      IMAGER => \&_f3,
    }
);

cmpthese $comp;
exit();

sub _f1 {
  my $im = new GD::Image(ImageFile) || die;
  my ($width,$height) = $im->getBounds();

  for( my $j=0; $j<$height; $j++ ){
    for( my $i=0; $i<$width; $i++ ){

      my ($r,$g,$b) = $im->rgb($im->getPixel($i,$j));

      my %RGB = (
        R => $r,
        G => $g,
        B => $b
      );
    }
  }
  return;
}

sub _f2 {
  my $im = Image::Magick->new();
  $im->Read(ImageFile);
  my ($w, $h) = $im->Get('width', 'height');

  my @color_list = $im->GetPixels(
    width  => $w,
    height => $h,
    x      => 0,
    y      => 0,
    map    => 'RGB'
  );

  while (@color_list > 0) {
    my %RGB = (
      R => int(shift @color_list) / 256,
      G => int(shift @color_list) / 256,
      B => int(shift @color_list) / 256
    );
  }
}

sub _f3 {

  my $im = Imager->new();
  $im->read( file=>ImageFile ) or die $im->errstr;

  for( my $j=0; $j<$im->getheight(); $j++ ){
    for( my $i=0; $i<$im->getwidth(); $i++ ){
      my $color = $im->getpixel( 'x'=>$i, 'y'=>$j );
      my ($r, $g, $b, $a) = $color->rgba();

      my %RGB = (
        R => $r,
        G => $g,
        B => $b
      );
    }
  }
}

自宅なんちゃってデータセンター

家に機器やPCが増えたので
全部一つの筐体に突っ込もうと考えた。

あと、ネットワークの勉強も兼ねて

  • ルータの作成・ルーティング
  • LANのセグメントを2系統にわけ、一方を DMZ
  • 仮想環境で複数サーバを勃起てたり起てなかったり。

をやろうと思った。

定額給付金もあるし、いまは何よりCPUもメモリも
お安い。


で、複数ホストに関してはどうせなら新しい
VirtualBox 3.0.4 を試してみましょう。


ちなみに Host は
CPU : Intel Quad
MEM : 8G
OS : CentOS 5.3 64bit


Guest として試したものは
CentOS 5.3 64bit
Solaris 10 64bit
Windows 7 RC 64bit


インストールは全てできたけど
安定して動いたのは CentOS だけ。。。


win 7 にいたっちゃ


「お兄さん。


 それ


 動いてないんですよ。」



ギィヤァアアアァアァァアぁぁああぁあぁ〜



と、稲川じゅんじさんの怪談オチ的に
気がついたら青い画面に向かって
キーボードを叩いている感じ。



やっぱ出たては良くないのかしら??



それにしても同じ sun なのに sola 10 まで。。。
(自分のスキルが悪いと思うけど)



でも vmware だと両者ともすんなり。



...うーん。


  • look & feel(古)
  • 画面のエミュレート

VirtualBox の方がいいんだけどなぁ...


続きはまた今度

ストアドからjavaのクラスを呼ぶ [ apache Derby (JavaDB) on winXP

使ったもの

java (SE) 1.5.0_11

DERBY_HOME、CLASSPATH 設定

C:\> set DERBY_HOME=C:\INSTALL_DIR
C:\> set CLASSPATH=%DERBY_HOME%\lib\derby.jar;%DERBY_HOME%\lib\derbyclient.jar;%DERBY_HOME%\lib\derbytools.jar;%DERBY_HOME%\lib\derbynet.jar;%DERBY_HOME%\lib\derbyrun.jar;%CLASSPATH%

INSTALL_DIR*1

db スキーマの保存ディレクトリを作成

C:\> mkdir DB_DIR

DB_DIR (好きな場所に。derby.system.home= に指定するパス)

設定ファイル(ファイル名::derby.properties)

## 認証の設定 ##
derby.connection.requireAuthentication=true
derby.authentication.propvider=BUILTIN

## ユーザ設定 ##
derby.database.fullAccessUsers=admin

## ユーザのパスワード設定 ##
derby.user.admin=admin

## ログの設定 ##
derby.infolog.append=append

DB_DIR 以下に置く
その他のプロパティ
ドキュメント全般

サーバ起動

C:\> java -Dderby.system.home=C:\DB_DIR org.apache.derby.drda.NetworkServerControl start
セキュリティーマネージャーが Basic サーバーセキュリティーポリシーを使用してインストールされました。
Apache Derby Network Server - YYYYY-MM-DD HH:MM:SS.937 GMT に 10.4.1.3 - (648739) が開始され、ポート 1527 で接続を受け入れる準備ができました。

コンソール(ij)起動

C:\> java -Dderby.system.home=C:\DB_DIR  org.apache.derby.tools.ij
ij バージョン 10.4
ij>_

コンソールからDB接続

ij> connect 'jdbc:derby://localhost:1527/test_db;user=admin;password=admin;create=true';

create=true*2
終了 ij > disconnrct;

テーブル、データの作成

ij>create table m_user (
     id   int not null,
     name varchar(32)
   );
0 行が挿入/更新/削除されました

ij>INSERT INTO m_user(id,name) VALUES(1,'nurai');
1 行が挿入/更新/削除されました

ij>SELECT * FROM m_user;
ID         |NAME
--------------------------------------------
1          |nurai

1 行が選択されました

java から接続

DBConnect.java
import java.sql.*;

public class DBConnect {
    private static String host    = "localhost";
    private static String user    = "admin";
    private static String passwd  = "admin";
    private static Connection con = null;

    public static Connection getConnect(String dbSchm) throws SQLException{
	try{
            Class.forName("org.apache.derby.jdbc.ClientDriver");
            String url = "jdbc:derby://" + host + ":1527/" + dbSchm;
            con = DriverManager.getConnection(url,user,passwd);
        }
        catch(ClassNotFoundException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        catch(SQLException e){
            throw e;
        }
        return con;
    }
}
TestClinet.java
import java.sql.*;

public class TestClient {
    public static void main(String[] args) {

        Connection con          = null;
        Statement stmt          = null;
        CallableStatement cstmt = null;
        ResultSet rs            = null;

        try{

            // test_db.m_user の内容を表示(接続確認)
            con  = DBConnect.getConnect("test_db");
            stmt = con.createStatement();
            rs   = stmt.executeQuery("SELECT * FROM M_USER");
            while(rs.next()){
                System.out.println("  id::" + rs.getInt(1));
                System.out.println("name::" + rs.getString(2));
            }
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if (rs != null) rs.close();
                if (cstmt != null) stmt.close();
                if (con != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
コンパイル & テスト
C:\src>javac DBConnect.java
C:\src>javac TestClient.java

C:\src>java TestClient
  id::1
name::nurai

プロシージャクラスの作成

MyProcedure.java
import java.sql.*;

public class MyProcedure {

    public static void addFirstName(int id, String firstName, ResultSet[] resultSet) throws SQLException {

        Connection con  = null;
        Statement  stmt = null;
        ResultSet  rs   = null;

        try{
            con = DriverManager.getConnection("jdbc:default:connection");
            stmt = con.createStatement();
            String qryString = "SELECT name FROM M_USER WHERE id=" + id;
            rs   = stmt.executeQuery(qryString);
            if(rs.next()){
                String addFirstName = rs.getString(1) + " " + firstName;
                System.out.println(addFirstName);
                stmt.executeUpdate("UPDATE M_USER SET name='" + addFirstName +"'");
                resultSet[0] = stmt.executeQuery(qryString);
            }
            return;
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if(con  != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}

プロシージャの作成

ij> DROP PROCEDURE M_USER.ADD_FIRST_NAME;
CREATE PROCEDURE M_USER.ADD_FIRST_NAME(
  id           INTEGER,
  firstName    VARCHAR(32)
)
MODIFIES SQL DATA
DYNAMIC RESULT SETS 1
PARAMETER STYLE JAVA
LANGUAGE JAVA
EXTERNAL NAME
'MyProcedure.addFirstName'
;
dbサーバにクラスパスの再設定を行い、再起動
C:\> set CLASSPATH="C:\src";%CLASSPATH%
C:\> java -Dderby.system.home=C:\DB_DIR org.apache.derby.drda.NetworkServerControl start
セキュリティーマネージャーが Basic サーバーセキュリティーポリシーを使用してインストールされました。
Apache Derby Network Server - YYYYY-MM-DD HH:MM:SS.937 GMT に 10.4.1.3 - (648739) が開始され、ポート 1527 で接続を受け入れる準備ができました。

MyProcedure の場所を derby に教える。

TestClinet.java を修正

import java.sql.*;

public class TestClient {
    public static void main(String[] args) {

        Connection con          = null;
        Statement stmt          = null;
        CallableStatement cstmt = null;
        ResultSet rs            = null;

        try{

            // test_db.m_user の内容を表示(接続確認)
            con  = DBConnect.getConnect("test_db");
            stmt = con.createStatement();
            rs   = stmt.executeQuery("SELECT * FROM M_USER");
            while(rs.next()){
                System.out.println("  id::" + rs.getInt(1));
                System.out.println("name::" + rs.getString(2));
            }

            //  ストアドプロシージャの呼び出し
            cstmt = con.prepareCall("{call M_USER.ADD_FIRST_NAME(?, ?)}");
            cstmt.setInt(1,1);
            cstmt.setString(2,"naoki");
            cstmt.execute();
            rs    = cstmt.getResultSet();
            while(rs.next()){
                System.out.println("=====");
                System.out.println("addFirstName::" + rs.getString(1));
            }
        }
        catch(SQLException e){
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        finally{
            try{
                if (rs != null) rs.close();
                if (cstmt != null) stmt.close();
                if (con != null) con.close();
            }
            catch(SQLException e){
                System.err.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
コンパイル & テスト
C:\src>javac MyProcedure.java
C:\src>javac TestClient.java

C:\src>java TestClient
  id::1

*1:Derby(JavaDB)をインストールしたディレクトリ

*2:指定したdbスキーマ[test_db]が無い場合、作成して接続

続きを読む

HyperEstraier + MeCab + perl バインディング

ウチの某案件で使うことになり

実際に触ってみました。

形態素解析MeCabを使います。

MeCabインストール

libiconv - 日本語パッチ
$ wget http://www2d.biglobe.ne.jp/~msyk/software/libiconv/libiconv-1.12-ja-1.patch.gz

libiconv

$ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.12.tar.gz
$ tar zxvf libiconv-1.12.tar.gz
$ cd libiconv-1.12
$ gzip -dc ../libiconv-1.12-ja-1.patch.gz | patch -p1
$ ./configure
$ make
$ sudo make install

QDBM

$ wget http://qdbm.sourceforge.net/qdbm-1.8.77.tar.gz
$ tar zxvf qdbm-1.8.77.tar.gz
$ cd qdbm-1.8.77
$ ./configure --enable-zlib
$ make
$ sudo make install
</code></pre>

MeCab

http://mecab.sourceforge.net/ から DL
$ wget --output-document=./mecab-0.97.tar.gz http://downloads.sourceforge.net/mecab/mecab-0.97.tar.gz?modtime=1202034262&amp;big_mirror=0
$ tar zxvf mecab-0.97.tar.gz
$ cd mecab-0.97
$ ./configure --enable-utf8-only --enable-mutex --prefix=/usr/local/mecab
$ make
$ sudo make install

mecab-ipadic

http://mecab.sourceforge.net/ から DL

$ wget --output-document=./mecab-ipadic-2.7.0-20070801.tar.gz http://downloads.sourceforge.net/mecab/mecab-ipadic-2.7.0-20070801.tar.gz?modtime=1185895550&amp;big_mirror=0
$ tar zxvf mecab-ipadic-2.7.0-20070801.tar.gz
$ cd mecab-ipadic-2.7.0-20070801
$ ./configure --with-charset=utf8 --with-mecab-config=/usr/local/mecab/bin/mecab-config
$ make
$ sudo make install

※ libiconv.so.2 がない!と怒られたときは、とりあえず
  /usr/local/mecab/lib 以下に、シンボリックリンクを張る

$ sudo ln -s /usr/local/lib/libiconv.so.2 ./libiconv.so.2
Hyper Estraier
$ wget http://hyperestraier.sourceforge.net/hyperestraier-1.4.13.tar.gz
$ tar zxvf hyperestraier-1.4.13.tar.gz
$ cd hyperestraier-1.4.13
$ ./configure --prefix=/usr/local/hyperestraier\
 --includedir=/usr/local/mecab/include\
 --libdir=/usr/local/mecab/lib\
 --libexecdir=/usr/local/mecab/libexec\
 --enable-mecab\
 --enable-dlfilter\
 --enable-regex
$ make
$ sudo make install
とりあえず動かす場合
  1. 適当なディレクトリを作ってstaticなコンテンツを置く
$ mkdir /tmp/contents

※ 自分は、mysql に入っているデータから 1レコード=1ファイルの tsv を作って置きました。

  1. ドキュメントルートにインデックスの作成
$ cd /var/www ( アタクシの環境の場合、/var/www )
$ sudo /usr/local/hyperestraier/bin/estcmd gather -il ja -sd /var/www/test_search /tmp/contents
  1. apache のデフォルト cgi-bin ディレクトリに、cgiもろもろファイルをコピー
$ mkdir /usr/local/apache/cgi-bin/fts
$ cp /usr/local/mecab/libexec/estseek.cgi /usr/local/apache/cgi-bin/fts/
$ cp /usr/local/hyperestraier/share/hyperestraier/estseek.* /usr/local/apache/cgi-bin/fts/
$ vi /usr/local/apache/cgi-bin/fts/estseek.conf
以下の 2 点を変更
indexname: /var/www/test_search
replace: ^file:///home/nurai/test/full_text/contents/{{!}}http://localhost/</code></pre>
  1. ブラウザからアクセス
http://localhost/cgi-bin/fts/estseek.cgi
hyperestraier-1.4.13.tar.gz の解凍したディレクトリ以下の perlnative に移動
$ ./configure
$ make
$ make install
適当なクラスを作成(とりあえず、catalystで使ってみる)
package FTS::Controller::Search;

use strict;
use warnings;
use base qw'Catalyst::Controller';

use Estraier;
$Estraier::DEBUG = 1;

my $DB  = Database->new;
$DB->open('/var/www/test_search', Database::DBREADER);
my $COND = Condition->new;

sub index : Private {
    my $self = shift;
    my ($c)  = @_;
    if($c->req->param('keyword')){
        $COND->set_phrase($c->req->param('keyword'));
        my $result = $DB->search($COND);
        my $dnum = $result->doc_num();
        for my $i (0..$result->doc_num){
            next if $result->get_doc_id($i) < 0;
            my $doc  = $DB->get_doc($result->get_doc_id($i), 0);

            # ここで、適当に値を取り出して表示
            print $doc->attr('@uri'), "\n";
        }
        return;
    }

    # ここで、適当な入力ページを表示
    return;
}
1;
__END__

以上!


... と思ったら http://search.cpan.org/~takeru/Catalyst-Model-Estraier-0.0.5/lib/Catalyst/Model/Estraier.pm

があった。。。org