《Erlang程序设计》第十五章 ETS和DETS:大数据的存储机制
第十五章 ETS和DETS:大數據的存儲機制
Table of Contents
- 第十五章 ETS和DETS:大數據的存儲機制
- 15.1 表的基本操作
- 創建和打開表
- 插入表
- 查找元組
- 釋放表
- 15.2 表的類型
- set表
- ordered set表
- bag表
- duplicate bag表
- 代碼示例
- 15.3 ETS表的效率考慮
- 15.4 創建ETS表
- 15.5 ETS程序示例
- 15.5.1 三字索引迭代器
- 15.5.2 構造表
- 15.5.3 構造表有多快
- 15.5.4 訪問表有多快
- 15.5.5 勝出的是…
- 15.6 DETS
- 15.7 我們沒有提及的部分
- 15.1 表的基本操作
第十五章 ETS和DETS:大數據的存儲機制
ETS和DETS都提供"鍵-值"搜索表, 只不過ETS駐留在內存而DETS駐留在磁盤, 因此ETS高效但數據存儲是臨時的, DETS數據存儲是持久的且節省內存但比較低效。
15.1 表的基本操作
創建和打開表
ets:new或dets:open_file
插入表
insert(TableName, X)
查找元組
lookup(TableName, Key)
釋放表
ets:delete(TableId)或dets:close(TableId)
15.2 表的類型
set表
每個元組的鍵值不能相同
ordered set表
排序的set表
bag表
多個元組可以有相同的鍵值, 但不能有兩個完全相同的元組
duplicate bag表
多個元組可以有相同的鍵值, 且同一個元組可以在表中出現多次
代碼示例
-module(ets_test). -export([start/0]).%% 分別以四種模式創建表并插入數據, 然后輸出表中的數據查看異同 start() ->lists:foreach(fun test_ets/1, [set, ordered_set, bag, duplicate_bag]).test_ets(Mode) ->TableId = ets:new(test, [Mode]),ets:insert(TableId, {a, 1}),ets:insert(TableId, {b, 2}),ets:insert(TableId, {a, 1}),ets:insert(TableId, {a, 3}),List = ets:tab2list(TableId),io:format("~-13w => ~p~n", [Mode, List]),ets:delete(TableId).? 運行結果:
15.3 ETS表的效率考慮
set表保證鍵值不相同, 因此相對耗費空間;ordered_set保證了排序, 因此相對耗費時間。
因為bag表插入數據時需要比較是否存在相同的鍵值, 因此如果大量元組存在相同鍵值, 使用bag表將會非常低效。
ETS表隸屬于創建它的進程, 隨進程消亡而消亡, 因此無需考慮垃圾回收。
盡可能的使用二進制數據。
15.4 創建ETS表
? 創建ETS表的函數原型
? 其中[Opt]的取值:
15.5 ETS程序示例
15.5.1 三字索引迭代器
%% 從壓縮文件中讀取英文單詞, 每個單詞都使用F函數處理 for_each_trigram_in_the_english_language(F, A0) ->{ok, Bin0} = file:read_file("354984si.ngl.gz"),Bin = zlib:gunzip(Bin0),scan_word_list(binary_to_list(Bin), F, A0).scan_word_list([], _, A) ->A; scan_word_list(L, F, A) ->%% 遍歷單詞, 在單詞前添加空格{Word, L1} = get_next_word(L, []),A1 = scan_trigrams([$\s|Word], F, A),scan_word_list(L1, F, A1).%% 單詞匹配, 遇到換行符則添加空格 get_next_word([$\r, $\n|T], L) ->{reverse([$\s|L]), T}; get_next_word([H|T], L) ->get_next_word(T, [H, L]); get_next_word([], L) ->{reverse([$\s|L]), []}.%% 創建三字索引 scan_trigrams([X, Y, Z], F, A) ->F([X, Y, Z], A); scan_trigrams([X, Y, Z|T], F, A) ->A1 = F([X, Y, Z], A),scan_trigrams([Y, Z|T], F, A1); scan_trigrams(_, _, A) ->A.15.5.2 構造表
%% 分別創建兩者類型的ets表 make_ets_ordered_set() ->make_a_set(ordered_set, "trigramsOS.tab"). make_ets_set() ->make_a_set(set, "trigramsS.tab").%% 根據指定類型創建ets表, 導入數據后轉成文件保存 make_a_set(Type, FileName) ->Tab = ets:new(table, [Type]),%% 聲明遍歷英文單詞時所使用的函數%% 這里將每個單詞插入到ets表F = fun(Str, _) ->ets:insert(Tab, {list_to_binary(Str)}) end,for_each_trigram_in_the_english_language(F, 0),%% 轉換為文件, 獲取記錄數后在內存中刪除ets表ets:tab2file(Tab, FileName),Size = ets:info(Tab, size),ets:delete(Tab),Size.make_mod_set() ->%% 使用sets存儲單詞D = sets:new(),F = fun(Str, Set) ->sets:add_element(list_to_binary(Str), Set) end,D1 = for_each_trigram_in_the_english_language(F, D),file:write_file("trigrams.set", [term_to_binary(D1)]).15.5.3 構造表有多快
%% 統計有多少個單詞 how_many_trigrams() ->%% 遇到一個單詞就將累加器增加1F = fun(_, N) ->1 + N end,for_each_trigram_in_the_english_language(F, 0).make_tables() ->%% 統計有多少個三字索引{Micro1, N} = timer:tc(?MODULE, how_many_trigrams, []),io:format("Counting - No of trigrams=~p time/trigram=~p~n", [N, Micro1/N]),%% 統計排序的ets表平均占用存儲和時間{Micro2, Ntri} = timer:tc(?MODULE, make_ets_ordered_set, []),FileSize1 = filelib:file_size("trigramsOS.tab"),io:format("Ets ordered Set size=~p time/trigram=~p~n", [FileSize1/Ntri, Micro2/N]),%% 統計普通ets表平均占用存儲和時間{Micro3, _} = timer:tc(?MODULE, make_ets_set, []),FileSize2 = filelib:file_size("trigramsS.tab"),io:format("Ets set size=~p time/trigram=~p~n", [FileSize2/Ntri, Micro3/N]),%% 統計使用set方式平均占用存儲和時間{Micro4, _} = timer:tc(?MODULE, make_mod_set, []),FileSize3 = filelib:file_size("trigrams.set"),io:format("Module sets size=~p time/trigram=~p~n", [FileSize3/Ntri, Micro4/N]).? 運行結果:
共有3 357 707個三字索引, 處理每個三字索引平均時間為0.15微秒;
ordered_set類型的ETS表平均每個三字索引占用19字節耗費0.62微秒;
普通類型的ETS表平均每個三字索引占用19字節耗費0.41微秒;
而使用Erlang的集合模塊平均存儲占用9字節耗費1.73微秒
15.5.4 訪問表有多快
lookup_all_ets(Tab, L) ->lists:foreach(fun({K}) ->ets:lookup(Tab, K) end, L).time_lookup_module_sets() ->%% 讀取文件轉成二進制數據{ok, Bin} = file:read_file("trigrams.set"),%% 二進制數據轉成列表Set = binary_to_term(Bin),Keys = sets:to_list(Set),Size = length(Keys),{M, _} = timer:tc(?MODULE, lookup_all_set, [Set, Keys]),io:format("Module set lookup=~p micro seconds~n", [M/Size]).%% 遍歷集合 lookup_all_set(Set, L) ->lists:foreach(fun(Key) ->sets:is_element(Key, Set) end, L).? 運行結果:
15.5.5 勝出的是…
%% 查詢某個字符串是否為單詞 %% 表中存儲時已經添加了空格, 因此這里要補全 is_word(Tab, Str) ->is_word1(Tab, "\s" ++ Str ++ "\s").%% 查詢符合[A, B, C]格式的字符串是否為單詞 is_word1(Tab, [_, _, _] = X) ->is_this_a_trigram(Tab, X); is_word1(Tab, [A, B, C|D]) ->case is_this_a_trigram(Tab, [A, B, C]) oftrue ->is_word1(Tab, [B, C|D]);false ->falseend; is_word1(_, _) ->false.%% 查詢ETS表中是否存在此索引 is_this_a_trigram(Tab, X) ->case ets:lookup(Tab, list_to_binary(X)) of[] ->false;_ ->trueend.%% 找到與源碼文件同目錄下的數據文件并轉換成ETS表 open() ->{ok, I} = ets:file2tab(filename:dirname(code:which(?MODULE)) ++ "/trigramsS.tab"),I.close(Tab) ->ets:delete(Tab).? 運行結果
15.6 DETS
如果在打開DETS文件后沒有關閉, 則Erlang將自動進行修復, 而修復可能會耗費大量的時間, 因此應在使用完后關閉DETS文件。
打開一個DETS表時, 要給出一個全局性的名字, 以便于多個進程用相同的名字和屬性來共享這個表。
代碼示例:
? 運行結果:
15.7 我們沒有提及的部分
ETS和DETS的在線手冊:
http://www.erlang.org/doc/man/ets.html
http://www.erlang.org/doc/man/dets.html
?
Date: 2013-12-07 10:30:38 CST
matrix.lisp@gmail.com
Org version 7.8.11 with Emacs version 24
Validate XHTML 1.0?
轉載于:https://www.cnblogs.com/scheme/p/3462508.html
總結
以上是生活随笔為你收集整理的《Erlang程序设计》第十五章 ETS和DETS:大数据的存储机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为了开篇
- 下一篇: 怎么知道网站是用什么程序做的