Nov 16, 2011

CentOS に 最新版の munin をインストール

epel の リポジトリがない場合は追加
rpm --import http://download.fedora.redhat.com/pub/epel/RPM-GPG-KEY-EPEL
rpm -ivh http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm
※ 上記は64bitマシン

epel の enabled を 0 にする。(お好みで)
# vi /etc/yum.repo.d/epel.repo

[epel]
name=Extra Packages for Enterprise Linux 5 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/5/$basearch
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch
failovermethod=priority
enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL

dag の リポジトリがない場合は追加
# vi /etc/yum.repo.d/dag.repo

[dag]
name=Dag RPM Repository for Red Hat Enterprise Linux
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
gpgkey=http://dag.wieers.com/rpm/packages/RPM-GPG-KEY.dag.txt
enabled=0

yum でインストール
yum --enablerepo=dag --enablerepo=epel install munin munin-node
※ munin, munin-node はそれぞれ必要に応じて



参考サイト
http://munin-monitoring.org/wiki/LinuxInstallation

Nov 15, 2011

Exim で SMTP ゲートウェイ の設定

/etc/exism/exim.conf の ROUTERS セクションの一番初めに以下の要領で記述します。

send_to_gateway:
  driver = manualroute
  domains = !+local_domains
  transport = remote_smtp
  route_list = * ispgw.smtp.host

これ、ROUTERS セクションの一番最後に追記して、全然設定が反映されず、数時間ハマってしまいました。。

参考サイト

http://www.hserus.net/wiki/index.php/Exim

Nov 1, 2011

javascript プロパティ値の存在チェック

単純に、プロパティが存在しているかチェック
'key' in obj

プロパティ継承を辿らず、自身のプロパティとして存在してるかチェック
obj.hasOwnProperty('key'); 

javascript ~~ 演算

n = ~~(n / 13);

13 で割って少数になった計算結果を整数に変換

Aug 31, 2011

vim で Java の setter / getter を自動で作成する

キーマッピングで以下の設定を .vimrc に追加します。

map Kk mawv/ <CR>"ty/ <CR>wve"ny/getters<CR>$a<CR><CR><Esc>xxa<Tab>public <Esc>"tpa<Esc>"npbiget<Esc>l~hea ()<CR>{<CR><Tab>return <Esc>"npa;<CR>}<Esc>=<CR><Esc>/setters<CR>$a<CR><CR><Esc>xxa<Tab>public void <Esc>"npbiset<Esc>l~hea (<Esc>"tpa<Esc>"npa)<CR>{<CR><Tab>this.<Esc>"npa = <Esc>"npa;<CR>}<Esc>=<CR>`ak

そして、Java のソースを例えば、以下のように書いたとすると、
クラス変数の private の最初のp のところで、マッピングしたキーを入力します。
(上の例だと Kk)

private int    id;
private String text = "initial value";
^(ここで Kk を入力すると、// getters, //setters の下に追加されます。)

// getters

// setters
 ↓
private int    id;
private String text = "initial value";

// getters

public String getText ()
{
    return text;
}

// setters

public void setText (String text)
{
    this.text = text;
}



しかし、この一連のマッピング、、見事です。。

※ 参考サイトのものを自分の環境に合わせて若干変えています。

参考サイト

http://vim.wikia.com/wiki/Generate_Java_setters_and_getters_automatically

Aug 25, 2011

build.xml に tomcat ant タスクの登録

tomcat manager を使用するので、tomcat6-admin-webapps をインストールします。。
reload タスクなどは、manager の URL に REST でコマンドを送って実行します。

yum --enablerepo=jpackage-generic install tomcat6-admin-webapps


tomcat-users.xml を編集して、admin role の userを設定

vi /etc/tomcat6/tomcat-users.xml

# 任意のユーザーを追加
<user name="USERNAME" password="PASSWORD" roles="admin" />



${catalina.home}/bin にある、catalina-tasks.xml を import してタスクを登録

<project>

...
<property name="catalina.home" value="/usr/share/tomcat6" />
<import file="${catalina.home}/bin/catalina-tasks.xml"/>

<!-- Reload tomcat -->
<target name="reload">
<reload url="http://localhost:8080/manager"
username="USERNAME"
password="PASSWORD"
path="/CONTEXT" />
</target>

...


${catalina.home}/bin/catalina-tasks.xml の中にある classpath の設定通りに jar ファイルがない場合は、
該当のファイルをclasspath に登録します。

私の場合は、シンボリックリンクを張りました。

cd /usr/share/java

sudo ln -s tomcat6-servlet-2.5-api-6.0.18.jar servlet-api.jar
sudo ln -s tomcat6-jsp-2.1-api-6.0.18.jar jsp-api.jar
sudo ln -s tomcat6-el-1.0-api-6.0.18.jar el-api.jar


参考サイト

http://www.neutralworks.com/blog/osx/mecurial-on-mac.html

Aug 19, 2011

Ant の native2ascii で「Couldn't load Kaffe's Native2Ascii class」

Ant のバージョンを上げると、解決するかもです。

以下のバージョンを、
ant-1.6.5

ant-nodeps-1.6.5


jpackageリポジトリの最新版、
ant-1.7.1

ant-nodeps-1.7.1

にアップデートすることで解決しました。


参考サイト

http://osdir.com/ml/java.ejbca.devel/2007-02/msg00007.html


Aug 18, 2011

VMware Fusion3: 共有 の設定で「 実行時フォルダの共有ステータスを更新できません:不明なエラー」が出る場合

gcc をインストールした後に、vmware-tools をインストール(再インストール)する。

参考サイトは、openSUSE の記述だけど、同じ方法で解決した。


参考サイト

http://www.vmware.com/jp/support/support-resources/pubs/view_pubs/releasenotes_fusion_312.html#gosissues

CentOS 5.5 に、mercurial のインストール

rpmforge のリポジトリにあるのをインストール。

rpmforge のインストールはこちら

yum --enablerepo=rpmforge install mercurial



参考サイト

http://d.hatena.ne.jp/red_snow/20100428/1272423744


OSX に、Mercurial のリポジトリを構築

macports を使って、mercurial をインストール
sudo port install mercurial


リポジトリの作成
※ パーミッション等、Apacheのユーザが書き込めるようにしておく
mkdir -p /path/to/hg/repo

cd /path/to/hg/repo
hg init someproject


hgrc の設置
vi /path/to/hg/repo/someproject/.hg/hgrc


# こんな感じ
[web]
contact = me@me.com
description = Some Project

allow_push = *
allow_archive = zip
push_ssl = true

# 詳しくは
man hgrc


hgweb.config の設置
vi /path/to/hg/hgweb.config


# こんな感じ
[paths]
/ = /path/to/hg/repo/*


hgweb.cgi の設置
cp /opt/local/share/mercurial/hgweb.cgi /path/to/hg/

vi /path/to/hg/hgweb.cgi

# 設定ファイルのパスを修正
config = "/path/to/hg/hgweb.config"

# 文字化けする場合は以下を追加
import os
os.environ["HGENCODING"] = "UTF-8"

# 以下必要に応じて書き換え
import sys; sys.path.insert(0, "/opt/local/Library/Frameworks/Python.framework/Versions/Current/lib/python2.6/site-packages")


Apacheの設定
sudo vi /etc/apache2/other/hg.config


# こんな感じ
Alias /hg /path/to/hg

<Directory "/path/to/hg">
Options ExecCGI FollowSymLinks
DirectoryIndex hgweb.cgi
AddHandler cgi-script .cgi

AuthType Basic
AuthName "Repository"
AuthUserFile /private/etc/apache2/.htpasswd
AuthGroupFile /dev/null

Order deny,allow
Deny from all
Allow from xxx.xxx.xxx.xxx/24

Require valid-user
</Directory>

# Apache再起動
sudo /usr/sbin/apachectl restart


参考サイト

http://www.neutralworks.com/blog/osx/mecurial-on-mac.html
http://blog.bluegold.me/2010/02/setup-mercurial-hgwebdir-fcgi-on-nginx/
http://d.hatena.ne.jp/eldesh/20110125/1295938971
http://www.proton.jp/main/programming/mercurial.html

Aug 13, 2011

centos 5.5 に、Apache + Tomcat6 な環境を作る

httpd のインストール
sudo yum install httpd


Tomcat のインストール
※ Jpackage のリポジトリを追加しておく。
※ webapps は必要に応じて。
sudo yum --enablerepo=jpackage-generic install tomcat6 tomcat6-webapps


ここで、以下のようなエラーが出る場合がある。
Missing Dependency: /usr/bin/rebuild-security-providers is needed


その場合は、jpackage-utils 5.0 を手動でインストールする。
sudo rpm -Uvh http://plone.lucidsolutions.co.nz/linux/centos/images/jpackage-utils-compat-el5-0.0.1-1.noarch.rpm



参考サイト

http://wiki.hillockhosting.com/yum/usrbinrebuild-security-providers-is-needed/

yum Jpackage リポジトリの追加

su -
rpm --import http://www.jpackage.org/jpackage.asc
wget http://www.jpackage.org/jpackage50.repo -O /etc/yum.repos.d/jpackage.repo
perl -p -i.old -e 's/enabled=1/enabled=0/' /etc/yum.repos.d/jpackage.repo

# 問題なければ
rm /etc/yum.repos.d/jpackage.repo.old


参考サイト

http://www.jpackage.org/

Jun 14, 2011

VMware fusion 3 の DHCP で、仮想マシンのIPアドレスを固定にする

/Library/Application Support/VMware Fusion/vmnet8/dhcpd.conf を編集してIPの設定を追加する。

$ sudo vi /Library/Application Support/VMware Fusion/vmnet8/dhcpd.conf

host dev1 {
    hardware ethernet 00:**:**:**:**:**; 
    fixed-address 192.168.***.***; 
}

その後、VMWare Fusion を終了し、dhcpd などのプロセスを再起動する。

$ cd /Library/Application Support/VMware Fusion/
$ sudo ./boot.sh --restart


参考サイト

http://www.linuxunbound.com/2010/04/static-ips-from-dhcpd-in-vmware-fusion/

Apr 7, 2011

Windows7 のタスクをコマンドで強制終了

1. PIDを確認する
> tasklist

2. 強制終了
> taskkill /F /PID pid

Apr 6, 2011

vim 現在行以降の置換

範囲指定の最初を空欄、最後を「$」に指定すると、現在行からファイルの最後までが検索対象になる。
:,$s/{検索文字列}/{置換文字列}/

Mar 2, 2011

自宅のMac から、会社のWindows を経由して、IP制限のかかった環境へSSH

会社のPCから、自宅の環境へVPNで接続し、会社のPCに立てた HTTP Proxyを介して、
IP制限された接続環境へ、http, https, ssh するようにしてみました。

VPN 接続

まず、自宅に、Linux でVPNサーバを立ち上げます。
PPTP接続の環境は簡単に構築できます。
「 CentOS pptpd 」などで検索すると色々出てきます。
私の自宅の環境は、だいぶ前に作って、詳細を掘り起こすのが、、、割愛します。
会社PC --->  自宅VPNサーバ

HTTP Proxy の設定

会社のPCに、Free Proxy などを使って、HttpProxy を立ち上げます。
自宅Mac -- (VPN) --> 会社Win (Http Proxy) --> (http, https, ssh) --> 目的サーバ

プロキシ構成ファイルの作成

http, https のアクセスは、制限のあるサーバだけをプロキシ経由にします。
そのため、例えば Mac の場合だと、以下にプロキシ構成ファイルを設定します。

システム環境設定 -> ネットワーク -> 詳細 -> プロキシ -> 自動プロキシ構成

プロキシ構成ファイル(.pac)の例
function FindProxyForURL(url, host) {
    var proxy = "PROXY mypc.at.office:8080";
    if (isPlainHostName(host)
        || shExpMatch(host,"client.server")) {
        return proxy;
    }
    return "DIRECT";
}


sshに、ProxyCommand の設定

まず、connect.c をインストールします。
curl http://www.meadowy.org/~gotoh/ssh/connect.c > connect.c
gcc connect.c -o connect -lresolv

~/.ssh/config の設定をします。
Host *.client.server
    ProxyCommand /path/to/connect -H mypc.at.office:8080 %h %p


参考サイト

http://www.gcd.org/sengoku/docs/NikkeiLinux00-12/config.ja.html
http://dsas.blog.klab.org/archives/50765770.html
http://bent.latency.net/bent/darcs/goto-san-connect-1.85/src/connect.html
http://findproxyforurl.com/

Feb 28, 2011

yaws 1.8.9 インストール

環境:
CentOS 5.5 i386 on VMware Fusion3
Erlang R14B01

pam-devel が必要なので、事前にインストール。
# yum install pam-devel
# ./configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/etc
# make && make install

Feb 23, 2011

Erlang のお勉強 自分用メモ 随時更新

浮動小数点の演算

/ での除算結果は、割りきれても必ず浮動小数点に変換される。
初めから浮動小数点の演算をしてるのかな?
1> 4/2.
2.0
2> 4 div 2.
2


アトム

小文字から始まる式は、全てアトムになる。
1> hello.
hello
2> Hello.
* 1: variable 'Hello' is unbound
3> hello=hello.
hello
4> Hello=hello.
hello
5> Hello.
hello


無名変数

「_」 は、何度でも代入している、不要な値を切り捨てるために使う変数。
1> Person={person,{name,calmoka},{age,36}}.
{person,{name,calmoka},{age,36}}
2> {_,{name,Name},_}=Person.
{person,{name,calmoka},{age,36}}
3> Name.
calmoka


文字列は整数のリスト

1> [99,97,116].
"cat"
2> [H|T]="cat".
"cat"
3> H.
99
4> T.
"at"


f() 変数の束縛状態を全て解除

1> X=123.
123
2> f().
ok
3> X=234.
234


リスト内包表記

リスト L から、Xを取り出して、F(X)した結果のリストを作成する。
[F(X) || X <- L].

1> [X * 2 || X <- [1,2,3,4,5]].
[2,4,6,8,10]


ガード

ガード列、G1;G2;G3...;Gn がtrueになるのは、ガード G1 ~ Gn の少なくともいずれか1つがtrueになる場合。
ガードは一覧のガード式を「,」で区切ったもの。
GuardExpr1, GuardExpr2, ..,GuardExprn がtrueになるのは、全てのガード式が true の場合。


and, andalso, or, orelse

and, or は全ての式を評価する。
andalso, orelse は評価がわかった時点で結果を出す。
f(X) = when (X == 0) or (1/X > 2) ...
g(X) = when (X == 0) orelse (1/X > 2) ...
X = 0 の時、f(X) は一致しない。


ガードで使えるBIF 例
is_atom(X)
is_binary(X)
is_constant(X)
is_float(X)
is_function(X)
is_function(X, N)     // 引数N個
is_integer(X)
is_list(X)
is_number(X)
is_pid(X)
is_port(X)
is_reference(X)
is_tuple(X)
is_record(X, Tag)
is_record(X, Tag, N)  // TagのレコードでNサイズ

abs(X)
element(N, X)  // タプルXのN番目の要素
float(X)
hd(X)          // リストXのヘッド
length(X)
node()         // 現在のノード
node(X)        // X(プロセス、リファレンス、ポート)が作られたノード
round(X)       // 整数に四捨五入
self()         // 現在のプロセスのPID
size(X)
trunc(X)       // Xを整数に切り捨てる
tl(X)          // リストXのテール
http://erldocs.com/R14B01/erts/erlang.html?i=0&search=erlang#undefined


レコードの定義

key=hoge とすると、hogeが初期値になる。
-record(rec, { key1=default, key2, key3 }).

% レコード定義は .hrl ファイル内で。

1> rr("record.hrl").
rec
2> X = #rec{key2=key2}.     
#rec{key1 = default,key2 = key2,key3 = undefined}

% rf() で、レコード定義をクリア、各変数はタプルになる。

3> rf(rec).
ok
4> X.
{rec,default,key2,undefined}


case文 で filter を書くと

filter(P, [H|T]) -> 
    case P(H) of
        true  -> [H|filter(P, T)];
        false -> filter(P, T)
    end;
filter(P, []) ->
    [].

case Expression of
    Pattern1 [When Guard1] -> Expr_seq1;
    Pattern2 [When Guard2] -> Expr_seq2
end

% ついでにif文

if
    Guard1 -> Expr_seq1;
    Guard2 -> Expr_seq2;
    true   -> Expr_seq3
end


リストは必ずヘッドに追加する

その方が効率がいいらしい。
並び順は逆になるがその場合最後に、lists:reverse/1 を呼び出す。
List ++ [H] は悪らしい。


アキュムレータ

一時的に保存する領域を使って関数を作る。
[H || filter(H)] よりも空間効率がいいらしい。

整数のリストを偶数と奇数のリストに分けるサンプル。
odds_and_evens(L) ->
    odds_and_evens(L, [], []).
    
odds_and_evens([H|T], Odds, Evens) ->
    case (H rem 2) of
        1 -> odds_and_evens(T, Odds, [H|Evens]);
        0 -> odds_and_evens(T, [H|Odds], Evens)
    end;
odds_and_evens([], Odds, Evens) ->
    {lists:reverse(Odds), lists:reverse(Evens)}.


1> lib_misc:odds_and_evens([1,2,4,5,6,7,8,89,3]).
{[2,4,6,8],[1,5,7,89,3]}



例外、エラー
exit(Why)          - プロセスを終了したい場合
throw(Why)         - 呼び出し側が補足する可能性がある例外
erlang:error(Why)  - クラッシュエラー 内部的に発生したエラーと同等


try catch のスタイル

エラーが起こることが多い場合は、try catch を使わずに戻り値で処理する。
case f(X) of
    {ok, Val}    -> ...;
    {error, Why} -> ...
end,

関数内で throw(Why) する場合は、
try f(X) of
    Val -> ...R
catch
    throw:{ExceptionA, Reason} -> ...;
    throw:{ExceptionB, Reason} -> ...;
    _:_ -> ...;
    exit:Ex  -> ...;
    error:Ex -> ...
end
通常は、exit は補足しないほうがイイ?
また、_:_, _ で補足できるのは、throw だけ。


ビット構文: 24ビットカラーのパック、アンパック
1> R = 16#ff.              
255
2> G = 16#66.
102
3> B = 16#00.
0
4> RGB = <<R:8, G:8, B:8>>.
<<255,102,0>>

5> <<R1:8, G1:8, B1:8>> = RGB.
<<255,102,0>>
6> R1.
255
7> G1.
102
8> B1.
0



アンダースコア変数

_ で始まる変数は、一度しか使われなくても警告が出ない。
そのため、「_」の代わりに切り捨てるデータに使うことが可能。


クラッシュダンプ

webtool で解析。
webtool:start().


プロセス タイムアウト付きの受信

receive
    Pattern1 [when Guard1] ->
        Expression1;
    Pattern2 [when Guard2] ->
        Expression2
    ...
after
    Time ->
        Expression
end.


on_exitハンドラ

プロセスが終了するときになにか処理をしたい場合は、
on_exit(Pid, F) を使う。


プロセスの終了時の処理

気にしないパターン
spawn(fun() -> ... end)
自分も死ぬ
spawn_link(fun() -> ... end)
死んだことを知りたい
process_flag(trap_exit, true),
spawn_link(fun() -> ... end)

loop() ->
    receive
        {'EXIT', Pid, Reason} -> ...
    end



関数を全てexportする
-compile(export_all).


パスの追加
パスの先頭に追加
$ erl -pa Dir1 -pa Dir2
> code:add_patha(Dir)

パスの末尾に追加
$ erl -pz Dir1 -pz Dir2
> code:add_pathz(Dir)

file_info のレコードファイル
-include_lib("kernel/include/file.hrl").


分散ノードの起動

クライアントとサーバが1つのホストで別ノード
-sname でショートネームを利用する設定にしてerlを起動
erl -sname node1
(node1@localhost)1> xxx:start().
ok
(node1@localhost)2> rpc:call(node2@localhost, M, F, A).
クライアントとサーバが別ホスト
-name -setcookie クッキーで同じクラスタに設定。
erl -name node1 -cookie somecookie
(node1@host1)1> xxx:start().
ok
(node1@host1)2> rpc:call(node2@host2.example.com, M, F, A).


Erlangで使いポートを設定して起動
elr -name ... -setcookie ... -kernel inet_dist_listen_min Min inet_dist_listen_max Max


インターネット上の別ホストで分散させる場合に開けておくポート

4369 の TCP/UDP epmd(Erlang Port Mapper Daemon)が利用する。


別ホストでプロセスを起動
spawn に Node名をつけて起動するだけ。他の関数も同様に第一引数がNodeになる。
spawn('somenode@somehost.example.com', Mod, Fun, Args).


別ホストで関数を実行
rpcモジュールの関数群を利用。
rpc:call(Node, Mod, Fun, Args).
など


フォーマットした文字列を取得

Str = lists:flatten(io_lib:format("foo ~p ~p", [bar, hoge])).


Dialyzer

PLTファイルを生成して、beamファイルかerlファイルを指定して解析する。
dialyzer --build_plt --apps erts kernel stdlib crypto compiler hipe
dialyzer -Wunmatched_returns -Werror_handling -Wrace_conditions ... -c hoge.erl


参考本

Feb 21, 2011

MacPortsのメンテナンス

MacPorts自体をアップデートする。

$ sudo port selfupdate

MacPorts にたまったキャッシュをクリアする。

$ sudo port clean --dist outdated
$ sudo port upgrade outdated
$ sudo port -u uninstall

clean のオプションは、man port で clean のセクションに詳細が書いてあります。

ちなみに、私の環境では約1年半メンテナンスしていなくて、約2.4G溜まっていたものが、
約1.2Gまで、スペースが空きました。


参考サイト

http://kunishi.blogspot.com/2009/04/macportstips-distfiles.html

Feb 17, 2011

詳細 Objective-C 2.0 随時更新 自分用メモ

通知センターでのぶらさがりポインタ注意ポイント P.361

通知センターに登録したオブザーバや、ポスト元として指定したオブジェクトは、
それらをreleaseする前に、通知センターから remove すること。
通知センターへの登録時に、retain されないので、ぶらさがりポインタになってしまう。


通知キュー

通知ポストの処理が終わるのを待たない場合は、通知キュー ( NSNotificationQueue ) を使う。
通知キューを使うと、非同期ポストと、同様のポストの統合が行われる。


_cmd

self と同様、暗黙のオブジェクトで、実行中のメソッドのSEL を表す。
- (id) hoge;
の場合、_cmd と、@selector(hoge) が同等になる。


リソースバンドル

リソースを取得する場合は、必ずロケールを意識した指定をすること。
NSString *path = [[NSBundle mainBundle] pathForResource:@"hoge" ofType:@"ext"];


iOSにおけるデバイスのアクセス

デバイスごとにファイルを分けてリソースバンドルで読み込む場合は、ファイル名を次のようにする。
 [ファイル名]~[デバイス名].拡張子
 image1~iphone.jpg
 image1~ipad.jpg

iPhone4用の高解像度の画像を用意する場合。
 [ファイル名]@2x.拡張子
 [ファイル名]@2x~[デバイス名].拡張子
 image2@2x~iphone.jpg
 image2~iphone.jpg
 image2~ipad.jpg

Info.plist の設定を分ける場合。
 [パラメータ名]~[デバイス名]
 UIInterfaceOrientation~ipad


アプリケーション名をローカライズ p.401

Info.plist
<key>CFBundleName</key>
<string>SpaSearch</string>
<key>CFBundleDisplayName</key>
<string>SpaSearch</string>

Japanese.lproj/InfoPlist.strings
CFBundleName = "温泉サーチ"
CFBundleDisplayName = "温泉サーチ(暫定版)"


ユーザーロケールの取得 p.402
id default = [NSUserDefaults standardUserDefaults];
id dic = [default dictionaryRepresentation];
id str = [[NSString alloc] initWithFormat:@"Data=%@" locale:dic, [NSDate date]];
みたいな。


アサーション
NSAssert(condition, NSString *description [, arg, ...]);
NSAssert(x > y, @"Illegal values x(%d) y(%d)", x, y);

コンパイル時に NS_BLOCK_ASSERTIONS というマクロを定義されていれば、
コードに組み込まれない。
gcc hoge.m ... -DNS_BLOCK_ASSERTIONS ...



Feb 16, 2011

lipo - OSXのユニバーサルバイナリをダイエット

lipo を使えば、PowerPC用など使わないバイナリを削除できます。

まず、情報をチェック。
$ cd /Applications/CotEditor.app/Contents/MacOS/
$ lipo -detailed_info CotEditor Fat header in: CotEditor
fat_magic 0xcafebabe
nfat_arch 2
architecture ppc
    cputype CPU_TYPE_POWERPC
    cpusubtype CPU_SUBTYPE_POWERPC_ALL
    offset 4096
    size 451032
    align 2^12 (4096)
architecture i386
    cputype CPU_TYPE_I386
    cpusubtype CPU_SUBTYPE_I386_ALL
    offset 458752
    size 457544
    align 2^12 (4096)

削除してよければ、例えば以下のように。
$ lipo -remove ppc -output CotEditor2 CotEditor

$ ll -h
total 2696
-rwxr-xr-x  1 user  admin   895K  4 26  2009 CotEditor
-rwxr-xr-x  1 user  admin   451K  2 16 23:14 CotEditor2

$ lipo -detailed_info CotEditor2
Fat header in: CotEditor3
fat_magic 0xcafebabe
nfat_arch 1
architecture i386
    cputype CPU_TYPE_I386
    cpusubtype CPU_SUBTYPE_I386_ALL
    offset 4096
    size 457544
    align 2^12 (4096)

起動してみて問題がなければ元のものと入れ替えます。


参考サイト

http://journal.mycom.co.jp/column/osx/282/index.html

Apache Solr 1.4 Filter の作成 DigitFilter, KatakanaStemFilter

以下、POSFilter と同様にして、
DigitFilter, KatakanaStemFilterを作成します。

各 Factory クラスは、create するだけなので、非常に単純で、以下のような内容です。
public class DigitFilterFactory extends BaseTokenFilterFactory {

    public TokenStream create(TokenStream input) {
        return new DigitFilter(input);
    }
}


そして、Filter クラスは以下のような感じです。
public class DigitFilter extends TokenFilter {
    boolean preRead;
    String preTerm;
    String preType;
    int    preStart;
    int    preEnd;

    protected DigitFilter(TokenStream input) {
        super(input);
        preRead = false;
        preTerm = preType = null;
        preStart = preEnd = 0;
    }

    public Token next(Token token) throws IOException {
        if (preRead) {
            preRead = false;
            return preTerm == null ?
                    null : token.reinit(preTerm, preStart, preEnd, preType);
        }

        Token t = input.next(token);
        if (t == null)
            return null;

        char[] c;  // for termBuffer

        if (t.termLength() == 1
          && Character.isDigit((c = t.termBuffer())[0])) {
            int start = t.startOffset();
            int end   = t.endOffset();
            String type = t.type();

            StringBuilder st = new StringBuilder();
            st.append(c[0]);
            while (true) {
                t = input.next(token);
                if (t == null) {
                    preRead = true;
                    preTerm = null;
                    break;
                }
                else if (t.termLength() != 1
                  || !Character.isDigit((c = t.termBuffer())[0])) {
                    preRead  = true;
                    preTerm  = new String(c, 0, t.termLength());
                    preStart = t.startOffset();
                    preEnd   = t.endOffset();
                    preType  = t.type();
                    break;
                }
                st.append(c[0]);
                end = t.endOffset();
            }
            return token.reinit(st.toString(), start, end, type);
        }
        return t;
    }
}

これで、以下の fieldType ができました。
<fieldType name="text_ja" class="solr.TextField">
    <analyzer>
      <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ja.txt" />
      <tokenizer class="SenTokenizerFactory" />
      <filter class="POSFilterFactory" deny="pos-deny.txt" />
      <filter class="DigitFilterFactory" />
      <filter class="solr.LowerCaseFilterFactory" />
      <filter class="KatakanaStemFilterFactory" />
      <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords-ja.txt" />
    </analyzer>
  </fieldType>

これで、SysnonymFilter も追加できますね。

※ 2/18 WordJoinFilter は問題があったので削除しました。

Apache Solr 1.4 Filter の作成 POSFilter

Tokenizer を作成したので、次はFilter を作ります。

Filter も Tokenizer と同様に、Factory クラスを作成し、Filter を create します。

Factoryクラスは、「 org.apache.solr.analysis.BaseTokenFilterFactory 」を継承し、
createメソッドを実装すればOKですが、設定ファイルをロードする必要がある場合などは、
「 org.apache.solr.util.plugin.ResourceLoaderAware 」を implement して、
inform メソッドを実装します。

このあたりは、Solr 本付属のソースや、
org.apache.solr.analysis.StopFilterFactory のソースなどが参考になります。

まずは、POSFilterFactory.class と、POSFilter.class を作成します。

POSFilterFactory.class で作成する 設定ファイルから読み込む POS情報ですが、
スレッド間で同期する必要がないので、Solr 本と同様に Set で実装します。

なので、POSFilterFactory のソースの抜粋は、以下のように。
public class POSFilterFactory extends BaseTokenFilterFactory implements ResourceLoaderAware {
    private Set<string> posSet;
    public void inform(ResourceLoader loader) {
        try {
            List<string> alist = loader.getLines(denyPOSFile);
            posSet = POSFilter.makePOSSet(alist);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public TokenStream create(TokenStream input) {
        return new POSFilter(input, posSet);
    }
}

public final class POSFilter extends TokenFilter {
    private final Set<string> posSet;

    public POSFilter(TokenStream input, Set<string> posSet) {
        super(input);
        this.posSet = posSet;
    }

    public final static Set<string> makePOSSet(List<string> posList) {
        if (posList == null)
            throw new NullPointerException("posList is null");
        return new HashSet<string>(posList);
    }

    public final Token next(Token token) throws IOException {
        Token t;
        while (true) {
            t = input.next(token);
            if (t == null)
                return null;
            if (posSet == null || !posSet.contains(t.type()))
                break;
        }
        return t;
    }
}


これで、fieldType の以下の部分までができました。
<fieldType name="text_ja" class="solr.TextField">
    <analyzer>
      <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ja.txt" />
      <tokenizer class="SenTokenizerFactory" />
      <filter class="POSFilterFactory" deny="pos-deny.txt" />
    </analyzer>
  </fieldType>

Apache Solr 1.4 Tokenizerの作成

JapaneseAnalyzer は、その名のとおり Analyzer クラ なので、schema.xml で細かなフィルターの設定はできません。
そこで、Tokenizerクラスを作成し、Filter、charFilter を柔軟に設定できる fieldType を作成します。

形態素解析には、同様に Sen を使用することとします。

TokenizerFactory を作る時は、「 org.apache.solr.analysis.BaseTokenizerFactory.class 」を実装し、
Factoryメソッドで、Tokenizer を作成します。
この辺りの流れは、ドキュメントを見るか、実際の solr や lucene のソースを見るのが参考になります。

JapaneseAnalyzer は、以下の流れで解析しています。

Reader を、NormalizeReader でラップし、全角⇔半角に文字を寄せる。
設定フィルで記述した tokenizerClass のインスタンスを作成。
POSFilter - 不要な型の term を除去
DigitFIlter - Senによって分割された数字を結合
LowerCaseFilter - 大文字を小文字に変換
KatakanaStemFilter - 4文字以降のカタカナの最後の「ー」を除去
StopFilter - stopwords を削除

最終的にはこのような fieldType を作成することを目標に、まずは、Tokenizerを作成します。

JapaneseAnalyzerを使うときは、システムプロパティからsen.home の値を取得しますが、
Solr 入門の本や、org.apache.solr.core.SolrResourceLoader.class の様に、
「 JNDI -> System Property -> デフォルト 」
とチェックするのがいいと思うので、そのように実装し、
sen/home は web.xml に記述することにします。

ただし、JapaneseAnalyzer を使う場合は、必ずシステムプロパティが必要なので、
同じ設定を2箇所に記述するよりは、システムプロパティに統一するほうがよさそうです。

そんなこんなで、Factoryクラスのソースは以下のような感じになります。
public class SenTokenizerFactory extends BaseTokenizerFactory {
  
    private static final Logger log
                    = LoggerFactory.getLogger(SenTokenizerFactory.class);

    static final String PROP_SEN_HOME = "sen.home";
    static final String JNDI_SEN_HOME = "sen/home";
    static final String FS = System.getProperty("file.separator");
    static final String SEN_XML = FS + "conf" + FS + "sen.xml";

    String configFile;
    String compositRule;

    @Override
    public void init(Map args) {
        String senHome = null;

        // Try JNDI
        try {
            Context c = new InitialContext();
            senHome = (String)c.lookup("java:comp/env/" + JNDI_SEN_HOME);
            log.info("Using JNDI sen/home: " + senHome);
        } catch (NoInitialContextException e) {
            log.info("JNDI not configured for Solr (NoInitialContextEx)");
        } catch (NamingException e) {
            log.info("No sen/home in JNDI");
        } catch (RuntimeException ex) {
            log.warn("Odd RuntimeException while testing for JNDI: " 
                    + ex.getMessage());
        } 

        // Now try system property
        if (senHome == null){
            senHome = System.getProperty(PROP_SEN_HOME);
            log.info("Using System property sen.home: " + senHome);
        }

        // Set current path
        if (senHome == null) {
            senHome = ".";
            log.info("sen.home defaulted to '.' (could not find system property or JNDI)");
        }

        configFile = senHome + SEN_XML;

        log.info( "config file for SenTokenizer is " + configFile );

        readConfig();

        log.info("conpositRule is: "
                + (compositRule == null ? "NULL" : compositRule));

    }

    protected String getConfigFile() {
        return configFile;
    }

    private void readConfig() {
        List<String> compositRuleList = new ArrayList<String>();

        try {
            DocumentBuilderFactory factory
                            = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(new InputSource(configFile));
            NodeList nl = doc.getFirstChild().getChildNodes();

            for (int i = 0; i < nl.getLength(); i++) {
                org.w3c.dom.Node n = nl.item(i);
                if (n.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    String nn = n.getNodeName();
                    String value = n.getFirstChild().getNodeValue();

                    if (nn.equals("composit")) {
                        compositRuleList.add(value);
                        log.info("add composit rule: " + value);
                    }
                }
            }

            if (compositRuleList.size() > 0) {
                compositRule = StringUtils.join(compositRuleList, "\n");
            }

        } catch (ParserConfigurationException e) {
            throw new IllegalArgumentException(e.getMessage());
        } catch (FileNotFoundException e) {
            throw new IllegalArgumentException(e.getMessage());
        } catch (SAXException e) {
            throw new IllegalArgumentException(e.getMessage());
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }

    public Tokenizer create(Reader input) {
        try {
            return new SenTokenizer(input, configFile, compositRule);
        } catch (IOException e) {
            throw new RuntimeException("cannot initialize SenTokenizer: "
                                        + e.toString());
        }
    }
}

そして、SenTokenizerクラスは以下のように。
public class SenTokenizer extends Tokenizer {

    private StreamTagger tagger       = null;
    private String       configFile   = null;
    private String       compositRule = null;

    private static final HashSet hash = new HashSet();

    public SenTokenizer(Reader input, String configFile, String compositRule)
            throws IOException {
        super(input);
        this.configFile = configFile;
        this.compositRule = compositRule;
        init(input);
    }
    
    private void init(Reader input) throws IOException {
        tagger = new StreamTagger(input, configFile);

        synchronized(hash) {
            if (compositRule != null && !compositRule.equals("")) {
                if (!hash.contains(compositRule)) {
                    CompositPostProcessor p = new CompositPostProcessor();
                    p.readRules(new BufferedReader(new StringReader(
                            compositRule)));
                    hash.add(compositRule);
                    tagger.addPostProcessor(p);
                }
            }
        }
    }

    public Token next(Token token) throws IOException {
        if (!tagger.hasNext())
            return null;

        net.java.sen.Token t = tagger.next();

        if (t == null)
            return next(token);

        return token.reinit(
                t.getBasicString(),
                correctOffset(t.start()),
                correctOffset(t.end()),
                t.getPos());
    }

    @Override
    public void reset(Reader input) throws IOException {
        super.reset(input);
        init(input);
    }
}

これで、fieldType の以下の部分までができました。
<fieldType name="text_ja" class="solr.TextField">
    <analyzer>
      <charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ja.txt" />
      <tokenizer class="mydomain.SenTokenizerFactory" />
    </analyzer>
  </fieldType>


追記:
2/18 sen.xml に、composit の設定を追加した際の処理をソースに追記しました。
まだマルチスレッドでうまく動作するかはテスト中です。



参考サイト

http://d.hatena.ne.jp/bowez/20090513


参考本

Feb 3, 2011

Apache Solr 1.4 Sen の辞書へ単語の追加

まずカスタム辞書を用意します。

カスタム辞書は以下の形式のCSVとします。

見出し語,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音

コストは単語の発生しやすさとのことです。小さい程よく発生する単語とのことで、
3000を基準に発生しやすいものは小さく、そうでないものは大きくするといいようです。

ある単語を登録する時に、何かの複合語になっている場合は、元のそれぞれの単語が
どの程度のコストで登録されているかを辞書ファイルを検索して調べると良いのかな?

あとは、カスタム辞書を用意して、ここでやったように、
辞書のCSVファイルの所に、カスタム辞書を追記して、antを実行して辞書を再生成します。

# vi $SEN_HOME/dic/build.xml

<arg line="customize_dic.csv dic.csv" />

# ant


しかし、、sen の辞書を追加(MkSenDic)したあとに、Tomcat を再起動しないとエラーになります。
実際には先にTomcatを停止した上で辞書の再生成をすることになると思いますが、どうにか起動したままできないものか。。



参考サイト



Feb 2, 2011

Apache Solr 1.4 スキーマの設定 schema.xml fieldType

Solr のスキーマの設定は、$SOLR_HOME/conf/schema.xml に記述します。

fieldTypeの設定

<fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>


sortMissingLast / SortMissingFirst の設定

sortMissingLast="true": ソートする際に値が空の場合に検索結果の最後に空の結果を配置する。
sortMissingFirst="true": ソートする際に値が空の場合に検索結果の最初に空の結果を配置する。

デフォルトは両方ともfalse。この場合は、以下のようになります。
昇順(asc)を指定した場合は、最初に空の結果を配置
降順(desc)を指定した場合は、最後に空の結果を配置

また、両方とも true にすると、いずれの場合も最後に配置されるようになります。

全パターンで試してみた所、どうやら sortMissingLastの設定が優先されるのかな?


omitNorms は、検索にヒットした時のスコアを計算する時の設定項目です。

平均値(Norm)を省略する(omit)かどうか、みたいな値です。

平均値とは、検索ワード/フィールドの文字長 の値で、この値が大きければスコアを上げるということになります。
元になるキーワードの量によって、スコアを変えたくない場合は、true に設定します。

ただし、boost 値を利用する場合は、omitNorms="false" にしておきます。

boost値とは、ドキュメントをアップロードする際に、各フィールドの重み付けをしたり、
検索クエリで、fieldname:value^boost のようにして、検索値の重み付けをすることができます。

この辺りがどう作用しているのかは、検索クエリに、debugQuery=on としてスコアの計算を見ることができます。


デフォルトで用意されているフィールドタイプ一覧

文字列、真偽、バイナリ

string
boolean(true, false)
binary(sent/retrived as Base64 encoded Strings)

数値、日付系

int
float
long
double
date

より速い範囲検索が必要な場合は、t~ を検討。

tint
tfloat
tlong
tdouble
tdate

以下は下位互換性のためにあるものなので、基本的には利用しない。

pint
plong
pfloat
pdouble
pdate

sint
slong
sfloat
sdouble

int, tint などは、いずれも solr.TrieXxxField の実装で、トライ木による木構造でIndexが生成されます。

違いは、precisionStepの値の設定。
しかし、precisionStep を変えるとどうなるのかは、分からなかった。。

schema.xml には以下のように書いてあるから、値が小さい方が範囲検索は速そう。

Smaller precisionStep values (specified in bits) will lead to more tokens
indexed per value, slightly larger index size, and faster range queries.
A precisionStep of 0 disables indexing at different precision levels.

でも、NumericField の、javadoc を見ると、デフォルト値は4になっており、
tint などでは、8に設定してあるから、デフォルトより大きい?と思ったり。。
これは今後の調査課題としておきます。


特殊なフィールドタイプ

random(ランダムソート時に利用)
ignored(完全に無視するフィールドに利用)

その他のカスタムフィールドタイプ

text_ws
text
textTight
textgen
text_rev
lowercase
....

これらがどういう働きをするかは、schema.xml を見ると分かります。


lucene-ja を使った、形態素解析のフィールドタイプは以下のように指定します。

<fieldType name="text_ja" class="solr.TextField">
 <analyzer class="org.apache.lucene.analysis.ja.JapaneseAnalyzer" />
</fieldType>

カスタムフィールドは、全て class="solr.TextField" と指定します。


これらたいていのことは、schema.xml を読めば、ほとんど説明が書いてあります。




Jan 31, 2011

Apache Solr 1.4 インストール on Tomcat

lucene-ja か、cmecab-java のどちらがいいか悩ましい。

検索エンジンの最新版を追わないのであれば、
JNI バインディングじゃない lucene-ja の方が好み。
でも、最新版を追いたくて、自分でメンテナンスする手間を省きたければ、
cmecab-java ってところか。

パフォーマンスは、両方の環境を作って比較するしかないかな。



環境:
CentOS 5.5 i386 on VMware Fusion3
Java6 SDK
Apache Ant
Apache Tomcat 5.5

インストールするもの:
Apache Solr 1.4
lucene-ja 2.0 + sen 1.2.2.1
cmecab-java + mecab 0.98


Apache Solr 1.4.1
download from http://www.apache.org/dyn/closer.cgi/lucene/solr/

# tar xzf apache-solr-1.4.1.tgz -C $INSTALL_DIR
# cd $INSTALL_DIR
# chown -R tomcat.tomcat apache-solr-1.4.1
# ln -s apache-solr-1.4.1 apache-solr
# export SOLR_HOME=$INSTALL_DIR/apache-solr


sen-1.2.2.1
インストール手順は /2011/01/sen-1221.html

Tomcat の起動オプションに sen.home を追加する。

# vi /etc/tomcat5/tomcat5.conf

JAVA_OPTS="$JAVA_OPTS -Dcatalina.ext.dirs=$CATALINA_HOME/shared/lib:$CATALINA_HOME/common/lib -Dsen.home=/usr/local/sen-1.2.2.1"


lucene-ja-2.0
インストール手順は /2011/01/lucene-ja-20.html




次にwebappsの設定

Tomcat に Solr の webapps を配置

# mkdir /var/lib/tomcat5/webapps/solr
# cd /var/lib/tomcat5/webapps/solr
# jar xf $SOLR_HOME/example/webapps/solr.war


sen.jar を webappsにコピーする。

# cp $SEN_HOME/lib/sen.jar /var/lib/tomcat5/webapps/solr/WEB-INF/lib


lucene-core.jar と lucene-ja.jar を webappsにコピーする。

# cd ~/lucene-ja/lib/
# cp lucene-core-2.0.0.jar lucene-ja-custom.jar /var/lib/tomcat5/webapps/solr/WEB-INF/lib/


solrのホームディレクトリを作成

サンプルをベースに利用します。

# cd $SOLR_HOME
# cp -a example/solr home

solrconfig.xml を編集して、データディレクトリを設定します。

# cd $SOLR_HOME
# vi home/conf/solrconfig.xml

  <dataDir>/usr/local/apache-solr/home/data</dataDir>


webapps の web.xml で、solr/home を設定します。

# vi /var/lib/tomcat5/webapps/solr/WEB-INF/web.xml

    <env-entry>
       <env-entry-name>solr/home</env-entry-name>
       <env-entry-value>/usr/local/apache-solr/home</env-entry-value>
       <env-entry-type>java.lang.String</env-entry-type>
    </env-entry>



Tomcat 起動

# /etc/init.d/tomcat5 start
# cat /var/log/tomcat5/catalina.out

ブラウザで、起動を確認する。

http://solrhost:8080/solr/


※ Tomcat の起動時に Xpath のエラーが出る場合は、xalan, xerces をインストールする。

download from http://xml.apache.org/xalan-j/downloads.html

# tar xzf xalan-j_2_7_1-bin-2jars.tar.gz
# cp xalan-j_2_7_1/*.jar /var/lib/tomcat5/shared/lib


※ 日本語の検索で文字化けする場合は、SetCharacterEncodingFilter を使う

ここではTomcat5のサンプルをそのまま利用します。

# cp SetCharacterEncodingFilter.class /var/lib/tomcat5/shared/classes/filters/
# vi /var/lib/tomcat5/webapps/solr/WEB-INF/web.xml

  <filter>
    <filter-name>Set Character Encoding</filter-name>
    <filter-class>filters.SetCharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>Set Character Encoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


# vi /etc/tomcat5/tomcat5.conf

    <Connector port="8080" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000" disableUploadTimeout="true"
               URIEncoding="UTF-8" useBodyEncodingForURI="true" />




参考サイト

http://lucene.apache.org/solr/tutorial.html
http://d.hatena.ne.jp/knaka20blue/20080922/1222104683
http://kazuakey.blogspot.com/2010/12/solr-14-sen.html
http://d.hatena.ne.jp/gnarl/20080912/1221189985

詳解 Objective-C 2.0 改訂版

Objective-C 面白い。

Mac App Store で提供できるアプリなんかできたらいいなと思って、お勉強中。

オブジェクトのメソッドを使う際に、メッセージを送信するっていうのに個人的にハマった。

ポリモーフィズム が id の型で柔軟に使えるのもいいし、まだまだ始めたばかりだけど、
言語の魅力にハマりそうな予感。


lucene-ja 2.0 インストール

Lucene を、Solr1.4 で利用する場合には、一部ソースの修正が必要です。


環境:
CentOS 5.5 i386 on VMware Fusion3
Java6 SDK


download from https://sen.dev.java.net/servlets/ProjectDocumentList?folderID=755&expandFolder=755&folderID=755


修正するソースは、org.apache.lucene.analysis.ja パッケージの以下4ファイルです。

DigitFilter.java
KatakanaStemFilter.java
MonitorFilter.java
POSFilter.java


コンストラクタ中の input = in; をコメントアウトします。

# unzip lucene-ja-2.0test2.zip
# cd lucene-ja/src/org/apache/lucene/analysis/ja/
# vi DigitFilter.java KatakanaStemFilter.java MonitorFilter.java POSFilter.java

// input = in;


build.xml を配置してコンパイル

# cd ~/lucene-ja
# ant
# ls -l lib/lucene-ja-custom.jar



参考サイト

http://ameblo.jp/miralis/entry-10290203004.html
http://kazuakey.blogspot.com/2010/12/solr-14-sen.html
http://d.hatena.ne.jp/gnarl/20080912/1221189985

mecab 0.9.8 インストール

環境:
CentOS 5.5 i386 on VMware Fusion3


C++ のコンパイラがない場合はインストールする。

# yum install gcc gcc-c++


Mecabのインストール
download from http://mecab.sourceforge.net/

$ tar xzf mecab-0.98.tar.gz
$ cd mecab-0.9.8
$ ./configure
$ make
$ su
# make install


確認

# mecab
すもももももももものうち
すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も 助詞,係助詞,*,*,*,*,も,モ,モ
もも 名詞,一般,*,*,*,*,もも,モモ,モモ
も 助詞,係助詞,*,*,*,*,も,モ,モ
もも 名詞,一般,*,*,*,*,もも,モモ,モモ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS


参考サイト

http://mecab.sourceforge.net/

sen 1.2.2.1 インストール 辞書をnaist-jdic にする

Mecab の Java移植版。
構築する辞書の文字コードを、サーバの文字コードと同じUTF-8に変更します。
また、ipadic の後継版である、NAIST Japanese Dictional を使うように修正します。

download from https://sen.dev.java.net/servlets/ProjectDocumentList?folderID=755&expandFolder=755&folderID=755


環境:
CentOS 5.5 i386 on VMware Fusion3
Apache Ant


sen 1.2.2.1 インストール

# unzip sen-1.2.2.1.zip -d $INSTALL_DIR
# export SEN_HOME=$INSTALL_DIR/sen-1.2.2.1


バグFIX

http://d.hatena.ne.jp/gnarl/20080912/1221189985

※ sen のコンパイルには、gcc-c++ などが必要です。


sen の辞書作成

a. 構築する辞書の文字コードを、utf-8 に変更する。(デフォルトは euc-jp)
b. NAIST-jdic の辞書を利用するように変更する。

文字コードの編集対象ファイルは、sen.xml, sen-processor.xml, dictionary.properties の3つです。
元々の辞書ファイルは、euc-jp で記述されており、その設定は変更しません。

# cd $SEN_HOME
# vi conf/sen.xml
   <charset>utf-8</charset>

# vi conf/sen-processor.xml
   <charset>utf-8</charset>

# vi dic/dictionary.properties
   sen.charset=utf-8


ChaSen 用の NAIST辞書ファイル(NAIST-jdic)をダウンロード。
http://sourceforge.jp/projects/naist-jdic/

# cp naist-jdic-0.4.3.tar.gz $SEN_HOME/dic/


build.xml の編集
ipadic の設定を、naist-jdic に変更します。
また同時に、OutOfMemoryError を回避するために、maxmemory を増やしておきます。

# cd $SEN_HOME/dic
# vi build.xml

  <target name="create" depends="dics0" unless="dics.present">
    <java classname="net.java.sen.tools.MkSenDic"
          fork="true"
          maxmemory="512m">


ipadic のファイル名を、naist-jdic に変更。

# diff build.xml build_naist-jdic.xml
17,19c17,19
<   <property name="ipadic.version" value="2.6.0"/>
<   <property name="ipadic.archive"  value="ipadic-${ipadic.version}.tar.gz"/>
<   <property name="ipadic.dir"  value="ipadic-${ipadic.version}"/>
---
>   <property name="ipadic.version" value="0.4.3"/>
>   <property name="ipadic.archive"  value="naist-jdic-${ipadic.version}.tar.gz"/>
>   <property name="ipadic.dir"  value="naist-jdic-${ipadic.version}"/>
56c56
<         <available file="ipadic-${ipadic.version}/Noun.dic"/>
---
>         <available file="naist-jdic-${ipadic.version}/Noun.dic"/>
89c89
<       <arg line="${ipa2mecab} ipadic-${ipadic.version}"/>
---
>       <arg line="${ipa2mecab} naist-jdic-${ipadic.version}"/>


辞書ファイルの生成

# ant

確認

# sh $SEN_HOME/bin/sen.sh
done.
Please input Japanese sentence:
[INFO] Dictionary - token file = /usr/local/sen-1.2.2.1/dic/token.sen
[INFO] Dictionary - time to load posInfo file = 22[ms]
[INFO] Dictionary - double array trie dictionary = /usr/local/sen-1.2.2.1/dic/da.sen
[INFO] DoubleArrayTrie - loading double array trie dict = /usr/local/sen-1.2.2.1/dic/da.sen
[INFO] DoubleArrayTrie - loaded time = 0.631[ms]
[INFO] Dictionary - pos info file = /usr/local/sen-1.2.2.1/dic/posInfo.sen
[INFO] Dictionary - time to load pos info file = 0[ms]
[INFO] Tokenizer - connection file = /usr/local/sen-1.2.2.1/dic/matrix.sen
[INFO] Tokenizer - time to load connect cost file = 91[ms]

無事に形態素解析されますか?
無事 (無事) 名詞-形容動詞語幹(0,2,2) ブジ ブジ
に (に) 助詞-副詞化(2,3,1) ニ ニ
形態素 (形態素) 名詞-一般(3,6,3) ケイタイソ ケイタイソ
解析 (解析) 名詞-サ変接続(6,8,2) カイセキ カイセキ
さ (する) 動詞-自立(8,9,1) サ サ
れ (れる) 動詞-接尾(9,10,1) レ レ
ます (ます) 助動詞(10,12,2) マス マス
か (か) 助詞-副助詞/並立助詞/終助詞(12,13,1) カ カ
? (?) 記号-一般(13,14,1) ? ?

すもももももももものうち
すもも (すもも) 名詞-一般(0,3,3) スモモ スモモ
も (も) 助詞-係助詞(3,4,1) モ モ
もも (もも) 名詞-一般(4,6,2) モモ モモ
も (も) 助詞-係助詞(6,7,1) モ モ
もも (もも) 名詞-一般(7,9,2) モモ モモ
の (の) 助詞-連体化(9,10,1) ノ ノ
うち (うち) 名詞-非自立-副詞可能(10,12,2) ウチ ウチ

在庫品SALE
在庫 (在庫) 名詞-サ変接続(0,2,2) ザイコ ザイコ
品 (品) 名詞-接尾-一般(2,3,1) ヒン ヒン
S (S) 記号-アルファベット(3,4,1) エス エス
A (A) 記号-アルファベット(4,5,1) エイ エイ
L (L) 記号-アルファベット(5,6,1) エル エル
E (E) 記号-アルファベット(6,7,1) イー イー

NAIST-jdic への移行は無事できましたが、ただ、英単語を分つことができない。。
原因はアルファベットが辞書に登録してあるためでした。

そこで、アルファベットを取り除いてみると。

# diff ipa2mecab_org.pl ipa2mecab.pl
188,189d187
<     next if ($pos2 eq 'アルファベット');
<

# ant
# sh $SEN_HOME/bin/sen.sh

在庫品SALE
在庫 (在庫) 名詞-サ変接続(0,2,2) ザイコ ザイコ
品 (品) 名詞-接尾-一般(2,3,1) ヒン ヒン
SALE (SALE) 未知語(3,7,4) null null

未知語でも良いので、連結してくれる方がいいよね。


さて、あとは、mecab用の最新の辞書を取込んでみたいところ。
mecab-naist-jdic-0.6.3-20100801/naist-jdic.csv
の方が約30,000語も多いし。。

どなたか NAIST-jdic for mecab の辞書を sen に取込む方法をご存知の方がいれば、
ご連絡くださいますと幸いです。


追記:

2/18
その後、sen.xml に、composit の設定を追加することによって、アルファベットや数字を結合できることが
分かりました。
そのため、辞書からアルファベットを取り除くよりも、composit を設定して結合する方がいいかと思い、
再度アルファベットを辞書に登録しました。
また、「-」をアルファベットとすると、wi-fi のような単語を作ることができるので、
- を記号、アルファベットとして、カスタム辞書に登録しました。
Sen は奥深いですね。関係者の方々に心から感謝です。


参考サイト

http://ultimania.org/sen/
http://kazuakey.blogspot.com/2010/12/solr-14-sen.html
http://d.hatena.ne.jp/gnarl/20080912/1221189985
http://d.hatena.ne.jp/code46/comment?date=20090531

Jan 28, 2011

Innodb deadlock など、問題があるときには

sql> show innodb status;

最新のデッドロックなどの状態が見れる。



参考サイト

http://dev.mysql.com/doc/refman/5.1/ja/innodb-monitor.html

yum 設定

yum-priorities のインストール

# yum install yum-priorities


公式リポジトリの優先度を1にしておく。

/etc/yum.repos.d/CentOS-Base.repo を編集し priority=1 を追加する。
base, uploads, addons, extras, centosplus, contrib の各リポジトリに設定を追加する。

# vi /etc/yum.repos.d/CentOS-Base.repo

[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5
priority=1
...



RPMforge のリポジトリをインストール

# rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# rpm -K rpmforge-release-0.5.2-2.el5.rf.i386.rpm
# rpm -ivh rpmforge-release-0.5.2-2.el5.rf.i386.rpm


※ デフォルトではOFFにして、-enablerepo=rpmforge のオプションをつけて利用する。

# vi /etc/yum.repos.d/rpmforge.repo

enabled=0



参考サイト



VMware Fusion3: /dev/hdc open failed

Setting up Logical Volume Management: /dev/hdc open failed: no medium found

仮想マシンの設定「CDとDVD」で、CD/DVDの接続のチェックを外していると上記エラーが出る。

特に無害なのでこのままでも問題ない。

VMware Fusion3: starging udev error

起動時に以下のエラーが発生する場合の対応。
基本的に無害なので未対応でもOK。

Starting udev:
udevd[572]: add_to_rules: unknown key 'SUBSYSTEMS'
udevd[572]: add_to_rules: unknown key 'ATTRS{vendor}'
udevd[572]: add_to_rules: unknown key 'ATTRS{model}'
udevd[572]: add_to_rules: unknown key 'SUBSYSTEMS'
udevd[572]: add_to_rules: unknown key 'ATTRS{vendor}'
udevd[572]: add_to_rules: unknown key 'ATTRS{model}'


/etc/udev/rules.d/99-vmware-scsi-udev.rule を編集し、未使用の行はコメントアウト、
RedHat系の場合は以下のように書き換える。

# vi /etc/udev/rules.d/99-vmware-scsi-udev.rule

ACTION=="add", BUS=="scsi", SYSFS{vendor}=="VMware, " , SYSFS{model}=="VMware Virtual S", RUN+="/bin/sh -c 'echo 180 >/sys$DEVPATH/device/timeout'"

To:

ACTION=="add", BUS=="scsi", SYSFS{vendor}=="VMware " , SYSFS{model}=="Virtual disk ", RUN+="/bin/sh -c 'echo 180 >/sys$DEVPATH/device/timeout'"

参考サイト

http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1023898

CD-ROMのマウント

手動

$ mount -t iso9660 -o ro /dev/cdrom /media


fstabに記述

# vi fstab

/dev/cdrom /media iso9660 noauto,owner,ro 0 0

.vimrc サンプル メモ

" vim: set ts=4 sw=4 sts=0:
"-----------------------------------------------------------------------------
" 文字コード関連
"
if &encoding !=# 'utf-8'
 set encoding=japan
 set fileencoding=japan
endif
if has('iconv')
 let s:enc_euc = 'euc-jp'
 let s:enc_jis = 'iso-2022-jp'
 " iconvがeucJP-msに対応しているかをチェック
 if iconv("\x87\x64\x87\x6a", 'cp932', 'eucjp-ms') ==# "\xad\xc5\xad\xcb"
  let s:enc_euc = 'eucjp-ms'
  let s:enc_jis = 'iso-2022-jp-3'
 " iconvがJISX0213に対応しているかをチェック
 elseif iconv("\x87\x64\x87\x6a", 'cp932', 'euc-jisx0213') ==# "\xad\xc5\xad\xcb"
  let s:enc_euc = 'euc-jisx0213'
  let s:enc_jis = 'iso-2022-jp-3'
 endif
 " fileencodingsを構築
 if &encoding ==# 'utf-8'
  let s:fileencodings_default = &fileencodings
  let &fileencodings = s:enc_jis .','. s:enc_euc .',cp932'
  let &fileencodings = &fileencodings .','. s:fileencodings_default
  unlet s:fileencodings_default
 else
  let &fileencodings = &fileencodings .','. s:enc_jis
  set fileencodings+=utf-8,ucs-2le,ucs-2
  if &encoding =~# '^\(euc-jp\|euc-jisx0213\|eucjp-ms\)$'
   set fileencodings+=cp932
   set fileencodings-=euc-jp
   set fileencodings-=euc-jisx0213
   set fileencodings-=eucjp-ms
   let &encoding = s:enc_euc
   let &fileencoding = s:enc_euc
  else
   let &fileencodings = &fileencodings .','. s:enc_euc
  endif
 endif
 " 定数を処分
 unlet s:enc_euc
 unlet s:enc_jis
endif
" 日本語を含まない場合は fileencoding に encoding を使うようにする
if has('autocmd')
 function! AU_ReCheck_FENC()
  if &fileencoding =~# 'iso-2022-jp' && search("[^\x01-\x7e]", 'n') == 0
   let &fileencoding=&encoding
  endif
 endfunction
 autocmd BufReadPost * call AU_ReCheck_FENC()
endif
" 改行コードの自動認識
set fileformats=unix,dos,mac
" □とか○の文字があってもカーソル位置がずれないようにする
if exists('&ambiwidth')
 set ambiwidth=double
endif

"-----------------------------------------------------------------------------
" 編集関連
"
"オートインデントする
set autoindent
"バイナリ編集(xxd)モード(vim -b での起動、もしくは *.bin で発動します)
augroup BinaryXXD
 autocmd!
 autocmd BufReadPre  *.bin let &binary =1
 autocmd BufReadPost * if &binary | silent %!xxd -g 1
 autocmd BufReadPost * set ft=xxd | endif
 autocmd BufWritePre * if &binary | %!xxd -r | endif
 autocmd BufWritePost * if &binary | silent %!xxd -g 1
 autocmd BufWritePost * set nomod | endif
augroup END

"-----------------------------------------------------------------------------
" 検索関連
"
"検索文字列が小文字の場合は大文字小文字を区別なく検索する
set ignorecase
"検索文字列に大文字が含まれている場合は区別して検索する
set smartcase
"検索時に最後まで行ったら最初に戻る
set wrapscan
"検索文字列入力時に順次対象文字列にヒットさせない
set noincsearch

"-----------------------------------------------------------------------------
" 装飾関連
"
"シンタックスハイライトを有効にする
if has("syntax")
 syntax on
endif
"行番号を表示しない
set nonumber
"タブの左側にカーソル表示
set listchars=tab:\ \ 
set list
"タブ幅を設定する
set tabstop=4
set shiftwidth=4
"タブをスペースにする
set expandtab
"入力中のコマンドをステータスに表示する
set showcmd
"括弧入力時の対応する括弧を表示
set showmatch
"検索結果文字列のハイライトを有効にする
set hlsearch
"ステータスラインを常に表示
set laststatus=2
"ステータスラインに文字コードと改行文字を表示する
set statusline=%<%f\ %m%r%h%w%{'['.(&fenc!=''?&fenc:&enc).']['.&ff.']'}%=%l,%c%V%8P

"-----------------------------------------------------------------------------
" マップ定義
"
"バッファ移動用キーマップ
" F2: 前のバッファ
" F3: 次のバッファ
" F4: バッファ削除
map <F2> <ESC>:bp<CR>
map <F3> <ESC>:bn<CR>
map <F4> <ESC>:bw<CR>
"表示行単位で行移動する
nnoremap j gj
nnoremap k gk
"フレームサイズを怠惰に変更する
map <kPlus> <C-W>+
map <kMinus> <C-W>-




参考サイト

忘れてしまった。。時間のある時に再度探します。ごめんなさい。。

CentOS 5.5 i386 on VMware Fusion3 インストール

OSインストール

とりあえずネットワークの設定だけして他は何も入れない。

http://www.centos.org/

最新の状態にアップデート

# yum check-update
# yum update


ntpのインストールと設定

# yum install ntp
# cp -a /etc/ntp.conf /etc/ntp.conf.org
# cat <<INPUT > /etc/ntp.conf
server 210.173.160.57
server 133.100.9.2
restrict default ignore
restrict 127.0.0.1
restrict 210.173.160.57 mask 255.255.255.255 noquery nomodify notrap notrust
restrict 133.100.9.2 mask 255.255.255.255 noquery nomodify notrap notrust
driftfile /etc/ntp/drift
authenticate no
INPUT

※ 上記 NTPサーバのIPアドレスは必要に応じて変更

参考サイト
http://www.ipa.go.jp/security/awareness/administrator/secure-web/chap4/4_ntpd.html
http://www.venus.dti.ne.jp/~yoshi-o/NTP/NTP-Table.html


時刻合わせ

# ntpdate 210.173.160.57


/etc/skel/ に設定追加

# cat <<INPUT >> /etc/skel/.bashrc
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias vi='vim'
INPUT

.vimrc も作成 .vimrcサンプル


ユーザー作成

# groupadd -g gid groupname
# useradd -u uid -g groupname username
# passwd username


/etc/ssh/sshd_config の設定

# vi /etc/ssh/sshd_config

PermitRootLogin no


/etc/inittab の設定

# vi /etc/inittab

tty2-6をコメントアウト


SELinux の無効化

# vi /etc/selinux/config

SELINUX=disabled


ホスト名の変更

# vi /etc/sysconfig/network

HOSTNAME=xxx.xxx.xxx


開発用ツールのインストール

# yum install kernel-headers
# yum install kernel-devel
# yum install gcc


サービス自動起動設定

// ON
# chkconfig ntpd on

// 状況に応じて
# chkconfig autofs off
# chkconfig iptables off
# chkconfig ip6tables off
# chkconfig irqbalance off
# chkconfig messagebus off

# chkconfig netfs off
# chkconfig nfslock off
# chkconfig portmap off
# chkconfig rpcgssd off
# chkconfig rpcidmapd off

# chkconfig anacron off
# chkconfig acpid off
# chkconfig apmd off
# chkconfig atd off
# chkconfig auditd off
# chkconfig avahi-daemon off
# chkconfig bluetooth off
# chkconfig cpuspeed off
# chkconfig --level 1 cpuspeed off
# chkconfig cups off
# chkconfig firstboot off
# chkconfig gpm off
# chkconfig haldaemon off
# chkconfig hidd off
# chkconfig isdn off
# chkconfig kudzu off
# chkconfig lvm2-monitor off
# chkconfig --level 1 lvm2-monitor off
# chkconfig mcstrans off
# chkconfig mdmonitor off
# chkconfig microcode_ctl off
# chkconfig pcscd off
# chkconfig rawdevices off
# chkconfig readahead_early off
# chkconfig readahead_later off
# chkconfig restorecond off
# chkconfig xfs off
# chkconfig sendmail off

# chkconfig smartd off

# chkconfig yum-updatesd off