ETS和DETS的介紹
ETS和DETS都是兩個(gè)系統(tǒng)模塊胰蝠,可以用來(lái)儲(chǔ)存海量的數(shù)據(jù)歼培,ETS的全稱是Erlang Term Storage(erlang 數(shù)據(jù)儲(chǔ)存),而Dets就是加了個(gè)Disk,磁盤ETS茸塞,他們的任務(wù)相同躲庄,提供大型的KV(Key-Value)查詢表,ETS比DETS高效钾虐,它儲(chǔ)存在內(nèi)存中噪窘,
一、ETS
表的類型
首先分為兩個(gè)大類:
- 異鍵表(set):要求鍵是唯一的
- 異鍵表
- 有序異鍵表(ordered set):元組會(huì)被排序
- 同鍵表(bag):允許多個(gè)元素使用同一個(gè)鍵效扫,但不能允許有鍵-值完全相同的元素存在
- 同鍵表
- 副本同鍵(duplicate bag)
表的操作
1.創(chuàng)建一個(gè)ETS表
-spec ets:new(TableName,[Option])-> TabeId when
TableName::atom().
Option:: [set | ordered_set | bag | duplicate bag,private | public | protected,named_table,{keypos,Pos}].
%% set | ordered_set | bag | duplicate bag 是表的類型上面有總結(jié)
%% private是創(chuàng)建一個(gè)私有表倔监,只有主管進(jìn)程(創(chuàng)建表的進(jìn)程)才可以讀寫它
%% public是創(chuàng)建一個(gè)公共表,只要知道TableId就可以讀寫它
%% protected是創(chuàng)建一個(gè)受保護(hù)表菌仁,只有主管進(jìn)程可以寫它浩习,其他進(jìn)程只可以讀
%% named_table 設(shè)置了這個(gè)選項(xiàng)之后,可以用TableName代替TableId對(duì)表進(jìn)行操作
%% {keypos,Pos}以元組的Pos位置作為鍵所在的位置济丘,通常為1
%% 當(dāng)Option是一個(gè)空列表谱秽,采用默認(rèn)值: [set,protected,{keypos,1}]
2.表的寫入
-spec ets:insert(TableId,[tuple()])-> bool() when
%% TableId是表的標(biāo)識(shí)符
%% [tuple()]是以擁有一個(gè)以上元素的元組為元素的列表洽蛀,[{key1,V1},{key2,V2}],可以向表寫入多個(gè)Key-Value
%% 舉例:
ets:insert(TableId,[{key1,123,{test,666}},{key2,456,abc}]).
表對(duì)鍵是否相同的判斷
這里要先介紹兩種判斷方法:
match
match相當(dāng)于精確判斷,不僅值要相同疟赊,類型也要相同郊供,例如1.0和1 雖然值相同,但是1.0是float類型 而1是integer類型-
compare equal
compare equal相當(dāng)于模糊判斷近哟,值相同即可Set類型的表采用match來(lái)判斷鍵是否重復(fù)驮审,ordered_set類型的表采用compare equal來(lái)判斷
3.表的讀取
-spec ets:lookup(TabId,Key)->[tuple()]
%% 返回一組符合要求的元組結(jié)果
除了使用lookup來(lái)查找,ets還提供了一些更為強(qiáng)大的查找方法:
-spec ets:match(TabId, Pattern) -> [Match]
%% Match可以是tuple中某些元素椅挣,也可以是全部元素
%% 舉例
test()->
TableId=ets:new(etsTable,[bag]),
ets:insert(etsTable,{key,value1,value2}),
io:format("matchResult:~p~n",[getMatch(TableId,{key,_,'$1'})]),
io:format("matchResult:~p~n",[getMatch(TableId,{key,'$2','$1'})]),
io:format("matchResult:~p~n",[getMatch(TableId,'$1')]).
getMatch(TabId,Pattern)->
ets:match(TabId,Pattern).
%% 輸出結(jié)果就是
%% [[value2]]
%% [[value2,value1]]
其中Pattern可以包含以下字符 1.一個(gè)綁定變量或者任意Erlang Term头岔;
2.一個(gè)占位符'_',可以匹配任何Erlang Term鼠证;
3.一個(gè)變量符'$N' (N可以為0,1,2,3....),該變量指定了match方法需要返回tuple中哪些元素靠抑;
若Pattern中包含Key值量九,那么查找起來(lái)非常快速(相當(dāng)于索引查詢)颂碧,否則需要全表遍歷
我們除了可以一次性查找出所有滿足匹配的tuples荠列,也可以采用"分頁(yè)查詢"的方式查詢,即每次只查詢出部分結(jié)果载城,然后通過迭代查找出所有結(jié)果:
-spec ets:match(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'
%% Continuation變量保存了下一個(gè)分頁(yè)的信息肌似,要獲取下一頁(yè)時(shí),只需要match(Continuation)即可獲取下一頁(yè)诉瓦,當(dāng)返回'$end_of_table'時(shí)沒有下一頁(yè)了
%% 例子:
test()->
TableId=ets:new(etsTable,[bag]),
ets:insert(etsTable,{key1,value1,value2}),
ets:insert(etsTable,{key1,value2,value1}),
{FirstMatch,Page2}=ets:match(TableId,{key1,'$1','$2'},1),%%一頁(yè)一條記錄
io:format("matchResult:~p~n",[FirstMatch])),
{SecondMatch,Page3}=ets:match(Page2),%%一頁(yè)一條記錄
io:format("matchResult:~p~n",[SecondMatch])),
Page3.
%% 輸出結(jié)果:
%% matchResult:[[value2],[value1]]
%% matchResult:[[value1],[value2]]
%% '$end_of_table'
4.最后我們來(lái)看下ets table的遍歷
-spec first(TableId) -> Key | '$end_of_table' %%用于獲取表中第一個(gè)Key
-spec next(TableId, Key1) -> Key2 | '$end_of_table' %%用于獲取Key1后面的Key
%%來(lái)個(gè)遍歷獲取{key,Value}的例子
listTable(TableId)->
case ets:first(TableId) of
'$end_of_table'->
io:format("啥都沒有讓我遍歷個(gè)啥~n");
Key->
Result=ets:lookup(TableId,Key),
io:format("Key: ~p Value:~p ~n",[Key,Result]),
listTable(TableId,Key).
listTable(TableId,Key)->
case ets:next(TableId,Key) of
'$end_of_table'->
io:format("到尾了兄弟~n");
Key2->
Result=ets:lookup(TableId,Key),
io:format("Key: ~p Value:~p ~n",[Key2,Result]),
listTable(TableId,Key2).
ets的其他函數(shù)
-spec delete(Tab, Key) -> true
%刪除表中某個(gè)KV
-spec delete(Tab) -> true
%刪除整個(gè)表
-spec all() -> [Tab]
%獲取目前所有表
-spec delete_all_objects(Tab) - > true
%刪除ETS表選項(xiàng)卡中的所有對(duì)象川队。該操作保證是 原子的和隔離的。
-spec delete_object(Tab睬澡,Object) - > true
%從ETS表中刪除確切的對(duì)象Object固额,保留具有相同鍵但具有其他差異的對(duì)象(對(duì)于類型包有用)。在duplicate_bag表中煞聪,將刪除該對(duì)象的所有實(shí)例斗躏。
-spec file2tab(FileSrc) - > {ok,Tab} | {error昔脯,Reason}
%讀取tab2file / 2或 tab2file / 3生成的文件啄糙,并創(chuàng)建相應(yīng)的表Tab。相當(dāng)于file2tab(Filename云稚,[])隧饼。
-spec tab2file(Tab, Filename) -> ok | {error, Reason}
%保存table到File
%....后面太多了 看手冊(cè)去吧
二、DETS
ETS把元組保存在內(nèi)存里碱鳞,而DETS把元組保存在磁盤上桑李,它的最大文件大小是2GB,DETS文件必須先打開才可以操作,用完以后還要正確關(guān)閉贵白。他們之間表的屬性也不一樣率拒,DETS在打開文件時(shí)必須賦予一個(gè)全局名稱,如果兩個(gè)或者更多的進(jìn)程以同一個(gè)名稱和選項(xiàng)打開了文件禁荒,他們就會(huì)共享這個(gè)表猬膨,直到所有進(jìn)程都關(guān)閉他,否則一直是打開狀態(tài)
%拿例子說(shuō)話
open(File)->
io:format("dets opened:~p~n",[File]),
Bool = filelib:is_file(File),
case dets:open_file(?MODULE,[{file,File}]) of
{ok,?MODULE}->
case Bool of
true->void;
false->ok=dets:insert(?MODULE,{free,1})
end,
true;
{error,Reason}->
io:format("cannot open dets table~n"),
exit({eDetsOpen,File,Reason})
end.
close()->
dets:close(?MODULE).
%這個(gè)例子是dets打開和關(guān)閉的例子呛伴,我們使用了模塊名作為表名
filename2index(FileName) when is_binary(FileName)->
case dets:lookup(?MODULE,Filename) of
[]->
[{_,Free}]=dets:lookup(?MODULE,free),
ok=dets:insert(?MODULE,[{Free,FileName},{FileName,Free},{free,Free+1}]),
Free;
[{_,N}]->
N
end.
%這個(gè)例子就包含了讀和寫
手冊(cè)內(nèi)推薦閱讀有關(guān)ETS和DETS的函數(shù)
- 基于模式獲取和刪除對(duì)象
- ETS和DETS勃痴、以及ETS表和文件之間的互相轉(zhuǎn)換
- 查看表的資源占用情況
- 遍歷表內(nèi)所有的元素
- 修復(fù)損壞的DETS表
- 讓表可視化
ETS表的各種方法:
ets:all/0
獲取所有的 ets 表
ets:delete/1
刪除整張表
ets:delete/2
刪除表里指定鍵的所有數(shù)據(jù)
ets:delete_all_objects/1
刪除表里的所有數(shù)據(jù)
ets:delete_object/2
刪除表里的指定數(shù)據(jù)
ets:file2tab/1
從一個(gè)文件讀取一個(gè) ETS 表
ets:first/1
獲取 ETS 表里的第一個(gè)對(duì)象數(shù)據(jù)的鍵
ets:foldl/3
對(duì) ETS 數(shù)據(jù)遍歷循環(huán)操作
ets:fun2ms/1
把語(yǔ)法函數(shù)轉(zhuǎn)為匹配規(guī)范的偽函數(shù)
ets:give_away/3
改變一個(gè)表的擁有者
ets:i/0
在輸出端上打印顯示所有 ETS 表的信息
ets:info/1
返回一個(gè) ETS 表的信息
ets:info/2
返回給出的跟表相關(guān)的項(xiàng)的信息
ets:insert/2
向 ETS 表插入數(shù)據(jù)
ets:insert_new/2
向 ETS 表插入新數(shù)據(jù)
ets:is_compiled_ms/1
檢測(cè)一個(gè) Erlang 數(shù)據(jù)是否是一個(gè)有效已編譯的匹配規(guī)范
ets:last/1
返回表里的最后一個(gè)鍵
ets:lookup/2
在 ETS 表里查出相應(yīng)鍵的值
ets:lookup_element/3
返回 ETS 表里指定鍵的對(duì)象數(shù)據(jù)的第幾個(gè)元素?cái)?shù)據(jù)
ets:match/1 | ets:match/2 | ets:match/3
根據(jù)匹配模式匹配表里的對(duì)象數(shù)據(jù)
ets:match_delete/2 | ets:match_object/1 | ets:match_object/2 | ets:match_object/3
根據(jù)匹配模式刪除表里的對(duì)象數(shù)據(jù)
ets:match_spec_compile/1
把一個(gè)匹配規(guī)范編譯為它的內(nèi)部表示形式
ets:match_spec_run/2
使用一個(gè)匹配規(guī)范來(lái)執(zhí)行匹配操作
ets:member/2
判斷表里面是否存在指定鍵的數(shù)據(jù)
ets:new/2
創(chuàng)建一個(gè) ets 表
ets:next/2
返回表的下一個(gè)鍵
ets:prev/2
返回表的上一個(gè)鍵
ets:rename/2
重新給 ETS 表命名一個(gè)名字
ets:safe_fixtable/2
鎖定一定 ETS 表使其可以安全遍歷
ets:select/1
對(duì) ETS 表里的數(shù)據(jù)進(jìn)行匹配比對(duì)
ets:select_delete/2
根據(jù)匹配模式刪除表里的對(duì)象數(shù)據(jù)
ets:tab2file/2 | ets:tab2file/2
把一個(gè) ETS 表轉(zhuǎn)儲(chǔ)到一個(gè)文件里
ets:tab2list/1
返回一個(gè) ETS 表的所有對(duì)象數(shù)據(jù)的列表
ets:to_dets/2
把內(nèi)存里的 ETS 數(shù)據(jù)插入到磁盤上保存
ets:update_element/3
更新 ETS 表里指定鍵的對(duì)象數(shù)據(jù)的第幾個(gè)元素?cái)?shù)據(jù)