日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《Erlang程序设计》第十五章 ETS和DETS:大数据的存储机制

發布時間:2025/4/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《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 我們沒有提及的部分

第十五章 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).

? 運行結果:

1> ets_test:start(). set => [{b,2},{a,3}] ordered_set => [{a,3},{b,2}] bag => [{b,2},{a,1},{a,3}] duplicate_bag => [{b,2},{a,1},{a,1},{a,3}] ok

15.3 ETS表的效率考慮

set表保證鍵值不相同, 因此相對耗費空間;ordered_set保證了排序, 因此相對耗費時間。
因為bag表插入數據時需要比較是否存在相同的鍵值, 因此如果大量元組存在相同鍵值, 使用bag表將會非常低效。
ETS表隸屬于創建它的進程, 隨進程消亡而消亡, 因此無需考慮垃圾回收。
盡可能的使用二進制數據。

15.4 創建ETS表

? 創建ETS表的函數原型

@spec ets:new(Name, [Opt]) -> TableId

? 其中[Opt]的取值:

# 表類型 set | ordered_set | bag | duplicate_bag# 權限 private 只有所有者進程可以讀寫 public 所有可以獲取TableId的進程都可以讀寫 protected 所有可以獲取TableId的進程都可以讀, 但只有所有者進程可以寫# 命名 named_table 是否可以使用Name來操作表# 指定鍵的位置 {keypos, K} 通常是第一個位置, 當需要存儲記錄時, 第一個位置是記錄的名字, 因此需要指定鍵的位置 # 默認選項為[set, protected, {keypos, 1}]

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]).

? 運行結果:

1> c(lib_trigrams). {ok,lib_trigrams} 2> lib_trigrams:make_tables(). Counting - No of trigrams=3357707 time/trigram=0.1504470163715893 Ets ordered Set size=19.029156153630503 time/trigram=0.6226862558287546 Ets set size=19.028408559947668 time/trigram=0.40671625010758833 Module sets size=9.433978132884777 time/trigram=1.728039700903027 ok

共有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).

? 運行結果:

1> lib_trigrams:timer_tests(). Ets ordered Set lookup=0.45313522100738246 micro seconds Ets set lookup=0.1906363891225119 micro seconds Module set lookup=0.31632557704887393 micro seconds ok

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).

? 運行結果

1> Tab = lib_trigrams:open(). 16402 2> lib_trigrams:is_word(Tab, "example"). true

15.6 DETS

如果在打開DETS文件后沒有關閉, 則Erlang將自動進行修復, 而修復可能會耗費大量的時間, 因此應在使用完后關閉DETS文件。
打開一個DETS表時, 要給出一個全局性的名字, 以便于多個進程用相同的名字和屬性來共享這個表。
代碼示例:

-module(lib_filenames_dets). -export([open/1, close/0, test/0, filename2index/1, index2filename/1]).open(File) ->io:format("dets opened:~p~n", [File]),Bool = filelib:is_file(File),%% 使用?MODULE宏獲取文件名作為TableNamecase dets:open_file(?MODULE, [{file, File}]) of{ok, ?MODULE} ->case Bool oftrue ->void;%% 插入鍵為free, 值為1的記錄, 用于統計表中記錄的總數false ->ok = dets:insert(?MODULE, {free, 1})end,true;{error, _Reason} ->io:format("cannot open dets table~n"),exit(eDetsOpen)end.close() ->dets:close(?MODULE).%% 將二進制格式的文件名插入到dets表 filename2index(FileName) when is_binary(FileName) ->%% 插入前先查詢文件名是否已經存在case dets:lookup(?MODULE, FileName) of[] ->%% 不存在則先查詢最大索引, 然后將索引-文件名, 文件名-索引, free-最大索引插入到dets表[{_, Free}] = dets:lookup(?MODULE, free),ok = dets:insert(?MODULE, [{Free, FileName}, {FileName, Free}, {free, Free+1}]), Free;%% 存在則直接返回索引值[{_, N}] ->Nend.%% 根據索引值查詢文件名 index2filename(Index) when is_integer(Index) ->case dets:lookup(?MODULE, Index) of[] ->error;[{_, Bin}] ->Binend.test() -> %% 每次測試都重建dets表file:delete("./filenames.dets"),open("./filenames.dets"),%% 使用正則查找當前目錄下的所有erl文件添加到dets表中F = lib_files_find:files(".", ".*[.](erl).*$", true),lists:foreach(fun(I) ->filename2index(list_to_binary(I)) end, F).

? 運行結果:

1> c(lib_filenames_dets). {ok,lib_filenames_dets} 2> lib_filenames_dets:test(). dets opened:"./filenames.dets" ok 3> lib_filenames_dets:index2filename(1). <<"./lib_trigrams.erl">> 4> lib_filenames_dets:index2filename(2). <<"./lib_files_find.erl">> 5> lib_filenames_dets:index2filename(3). <<"./lib_filenames_dets.erl">> 6> lib_filenames_dets:index2filename(4). <<"./ets_test.erl">> 7> lib_filenames_dets:filename2index(list_to_binary("./ets_test.erl")). 4

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

Author: matrix

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0

?

轉載于:https://www.cnblogs.com/scheme/p/3462508.html

總結

以上是生活随笔為你收集整理的《Erlang程序设计》第十五章 ETS和DETS:大数据的存储机制的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。