2007年09月27日

erlang:dets の動作を調べる(その1)

はてなブックマークに登録

以前紹介した付箋webを開発する際に、Erlang のストレージシステムの一つである dets を使用しました。

この dets の基本的な使い方と、動作についてよくわからない所があったので、実験とその結果を書いてみたいと思います。

detsのデータベースを作る

Erlangを起動してdetsファイルを作ります。

~/work$erl
Erlang (BEAM) emulator version 5.5.5 [source] [async-threads:0] [kernel-poll:false]

Eshell V5.5.5  (abort with ^G)
1> {ok,Ref}=dets:open_file(dets1.file,[]).
{ok,'dets1.file'}

ファイルができました。

~/work$ls -l
total 8
-rw-r--r-- 1 klab klab 5432 Sep 21 15:28 dets1.file
~/work$

open_file()の引数(dets1.file)はatomですが、第2引数で指定するリストで指 定しなければatomがそのままファイル名になります。 大文字で始まるファイル名の場合は、' 'で囲めばatomとして扱ってくれます。 ファイル名をatomとは別に指定したいときは[{file,"FILENAME"}]のようなオ プションを指定します。

成功すると{ok,Ref}のタプルを返します。Refにはatomが入ります。オープン 後detsを操作するのはRefでもatomのdets1.fileでも同じです。 作成されたdetsの情報はinfo()で調べられます。

2> Ref.
'dets1.file'
3> dets:info(dets1.file).
[{type,set},{keypos,1},{size,0},{file_size,5752},{filename,"dets1.file"}]

テスト中に文の間違いなどでエラーを起こすとatomが無効にされるので、時々 info()でチェックしたほうがいいでしょう。 クローズします。

5> dets:close(Ref).
ok

データを挿入します。
(何度かErlangを起動し直したり、文書の順番を整理しているのでプロンプト の番号は順番になっていません。)

2> dets:insert(dets1.file,{neko,{"TAMA","4"}}).
ok
3> dets:insert(dets1.file,{inu,{"TARO","5"}}).
ok

デフォルトは、detsやetsに書き込むデータは、最初の要素をキーにした2要 素のタプルになります。
この場合、'3>'だとキーはinu でデータは {"TARO","5"}です。

キーで検索する

次は、キーを使った簡単な検索をします。

140> dets:lookup(dets1.file,neko).
[{neko,{"TAMA","4"}}]
141> dets:lookup(dets1.file,nai).
[]

データがないと空リストを返します。
member()でレコードの有無の確認

142> dets:member(dets1.file,neko).
true
143> dets:member(dets1.file,nai).
false

キーはfirst()とnext()で取得できます。
(テスト中にデータを追加しています。)

145> dets:first(dets1.file).
rabit
146> dets:next(dets1.file,rabit).
neko

最後にnext()を実行すると'$end_of_table'が返ります。
存在しないキーをnext()に渡すと、errorでは無く不定のキーが返るようです。???

147> dets:next(dets1.file,1).
'$end_of_table'
148> dets:next(dets1.file,nai).
rat

match()でdetsを検索する

まず、match()を使ってみます。 マニュアルはここ

35> dets:match(dets1.file,'$1').
[[{neko,{"TAMA","4"}}],
 [{inu,{"TARO","5"}}],
 [{rat,{"happy","6"}}],
 [{rabit,{"pyon","7"}}]]

matchの第2引数はパターンを記述しますが、'$N'はパターン変数で'$1'を指 定すると全部のレコートが返ってきます。 matchはetsでも使えます。次のmatch()では"T"で始まる内容の2番目の内容 がリストで返されています。

47> dets:match(dets1.file,{'_',{"T"++'_','$1'}}).
[["4"],["5"]]

次の例では、48>ではキーがratのデータのタプルを返し、 49>ではパターン変数で指定した位置の文字がリストで返されています。

48> dets:match(dets1.file,{rat,'$1'}).
[[{"happy","6"}]]
49> dets:match(dets1.file,{rat,{'$1','$2'}}).
[["happy","6"]]

パターン変数の番号が飛んでいる場合は、結果も飛ばされるようです。

50> dets:match(dets1.file,{'$3',{"T"++'_','$1'}}).
[["4",neko],["5",inu]]

select()でdetsを検索する。

次に、select()
35> dets:match(dets1.file,'$1'). と同じselect()は

66> dets:select(dets1.file,[{'$1',[],['$$']}]).
[[{neko,{"TAMA","4"}}],
 [{inu,{"TARO","5"}}],
 [{rat,{"happy","6"}}],
 [{rabit,{"pyon","7"}}]]

第2引数はマッチパターンから、パターンを含むマッチスペックになります。
マニュアルより

    * MatchSpec = [MatchFunction]
    * MatchFunction = {MatchHead, [Guard], [Result]}
    * MatchHead = "Pattern as in ets:match"
    * Guard = {"Guardtest name", ...}
    * Result = "Term construct"

マッチスファンクションの第3要素のリザルトを'$$'から'$_'に変えると結果 のリストのリストだったのが結果のリストになりました。

67> dets:select(dets1.file,[{'$1',[],['$_']}]).
[{neko,{"TAMA","4"}},
 {inu,{"TARO","5"}},
 {rat,{"happy","6"}},
 {rabit,{"pyon","7"}}]

テストのためキーが数字のレコードを追加します。

102> dets:insert(dets1.file,{1,{by2,2}}).
ok

ガードのテストです。キーがatomのものを選択します。

103> dets:select(dets1.file,[{{'$1','$2'},[{'is_atom','$1'}],['$$']}]).
[[neko,{"TAMA","4"}],
 [inu,{"TARO","5"}],
 [rat,{"happy","6"}],
 [rabit,{"pyon","7"}]]
キーが数字のものを選択します。
104> dets:select(dets1.file,[{{'$1','$2'},[{'is_number','$1'}],['$$']}]).
[[1,{by2,2}]]
キーが0以上のものを選択します。atomの場合も含むようです。
105> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',0}],['$$']}]).
[[neko,{"TAMA","4"}],
 [inu,{"TARO","5"}],
 [rat,{"happy","6"}],
 [rabit,{"pyon","7"}],
 [1,{by2,2}]]
キーが1以上のものを選択します。
106> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',1}],['$$']}]).
[[neko,{"TAMA","4"}],
 [inu,{"TARO","5"}],
 [rat,{"happy","6"}],
 [rabit,{"pyon","7"}]]

上記のリザルトを変えてみます。['$$']から['$1']に変更しました。$1はキー がある位置なのでキーのリストが返ってきます。

107> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',1}],['$1']}]).
[neko,inu,rat,rabit]
リザルトを['$2']にすると、$2はデータのタプルの位置にあるので、タプルの リストが返ってきます。
123> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',1}],['$2']}]).
[{"TAMA","4"},{"TARO","5"},{"happy","6"},{"pyon","7"}]
リザルトを[{{'$1','$2'}}]にしてみました。
124> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',1}],[{{'$1','$2'}}]}]).
[{neko,{"TAMA","4"}},
 {inu,{"TARO","5"}},
 {rat,{"happy","6"}},
 {rabit,{"pyon","7"}}]
リザルトを[{{'$1',"YOKUWAKARANAI"}}]にしてみました。
135> dets:select(dets1.file,[{{'$1','$2'},[{'>','$1',1}],[{{'$1',"YOKUWAKARANAI"}}]}]).
[{neko,"YOKUWAKARANAI"},
 {inu,"YOKUWAKARANAI"},
 {rat,"YOKUWAKARANAI"},
 {rabit,"YOKUWAKARANAI"}]
成功例だけ、ご参考まで。
#エラーのたびに、open_file()が必要でした。

マッチスペックを関数から作る

selectで使用したマッチスペック(MatchSpec)ですが、これを関数から変換す る関数(ets:fun2ms/1)があります. 上の例でマッチスペック
[{{'$1','$2'},[{'>','$1',1}],[{{'$1','$2'}}]}]
はets:fun2ms()を使って、関数を変換することで作ることができます。

1> dets:open_file(dets1.file,[]).
{ok,'dets1.file'}
2> ets:fun2ms(fun({N1,N2})when N1 > 1 -> {N1,N2} end).
[{{'$1','$2'},[{'>','$1',1}],[{{'$1','$2'}}]}]

作成したマッチスペックを使ってselectを実行しました。

3> MS=ets:fun2ms(fun({N1,N2})when N1 > 1 -> {N1,N2} end).
[{{'$1','$2'},[{'>','$1',1}],[{{'$1','$2'}}]}]
4> dets:select(dets1.file,MS).
[{neko,{"TAMA","4"}},
 {inu,{"TARO","5"}},
 {rat,{"happy","6"}},
 {rabit,{"pyon","7"}}]

ガードで使える関数は決まっていて、http://www.erlang.org/doc/man/erlang.html で書かれているBIFs(built-in functions)の中の"Allowed in guard tests" と書かれている関数だけになります。http://d.hatena.ne.jp/n_shuyo/20070510/erlang にまとめてくれていました。

以下はis_number とis_atomを使った例です。

14> MS1 = ets:fun2ms(fun({N1,N2})when is_number(N1)-> {N1,N2} end).
[{{'$1','$2'},[{is_number,'$1'}],[{{'$1','$2'}}]}]
19> dets:select(dets1.file,MS1).
[{1,{by2,2}}]
50> MS2=ets:fun2ms(fun({N1,{N2,N3}}) when is_atom(N1) -> {N1,N2} end).
[{{'$1',{'$2','$3'}},[{is_atom,'$1'}],[{{'$1','$2'}}]}]
53> dets:select(dets1.file,MS2).
[{neko,"TAMA"},{inu,"TARO"},{rat,"happy"},{rabit,"pyon"}]

次回に続きます。

klab_gijutsu2 at 19:47│Comments(0)TrackBack(0)Erlang 

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント