Elang之ETS系列函数功能与用法详解

来源:互联网 发布:淘宝禁售电话卡和天猫 编辑:程序博客网 时间:2024/05/17 23:19
ets表格创建参数
set,ordered_set,bag,duplicate_bag
指定创建的table类型。
set:table中的每一个Value(Tuple)都是唯一,并且一个Key只能对应一个Value;
order_set:同set,唯一不同的是table中的Key是有序的;
bag:table中的每一个Value都是唯一的,但是一个key可以对应多个Value;
duplicate:table中每个key可以对应多个value,并且允许Value重复
public
private
protected
指定table的访问权限。
public:所有进程都可以对该表进行读写
private:只有创建表的进程可以对table进行读写
protected:所有的进程都可以对表今次那个读取,只有创建表的进程可以进行写操作
named_table若是指定了named_table这个属性,就可以使用表名对表进行操作,而无需使用Tableid{KeyPos,Pos}
一般默认使用tuple中第一个元素作为Key,通过设置{KeyPos,Pos}可以指定Key的位置,
Pos表示使用tuple中的第几个元素作为Key
{heir,Pid,HeriData}
{heir,none}
这个heir属性指明当创建table的process终止时,是否有其他process来继承这个table,默认值是{heir,none},表示没有继承者,所以当创建表的process终止时,表也随之被delete;若我们指定了{heir,Pid,HeirData},那么当创建表的process终止时,process identifer为Pid的process将会收到一个消息:{'ETS-TRANSFER',tid(),FromPid,HeirData},这样表的拥有权就转交了

[作者:点A点C]
最常用函数:
new(Name, Options) -> tid() | atom()
新建一个表名为Name的ETS表,并返回表的一个标识符。
     Types:
                 Name = atom()
                 Options = [Option]
                 Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | Tweaks
                 Type = set | ordered_set | bag | duplicate_bag
                 Access = public | protected | private
                 Tweaks = {write_concurrency,boolean()} | {read_concurrency,boolean()} | compressed
                 Pos = integer()
                 HeirData = term()

tab2list(Tab) -> [Object]
返回一个ETS表的所有对象数据的列表
     Types:
           Tab = tab()
          Object = tuple()


增/插入:
insert(Tab, ObjectOrObjects) -> true
向ETS表Tab中插入一个或一个对象列表数据ObjectOrObjects
如果是set类型和orderen_set类型的表,插入的数据和表里的数据有相同的键值,则旧数据会被替换
insert_new(Tab, ObjectOrObjects) -> boolean()
与insert/2类似,但当插入的对象是一个列表,则在插入数据前,将检测列表里的每一个键,如果有和表中键值相同的则不插入任何数据对象。

删/删除:
delete(Tab) -> true
     Types:
          Tab = atom() |tid()
删除整个Tab表

delete(Tab, Key) -> true
     Types:
          Tab = atom() | tid()
          Key = trem()
从Tab表中删除所有以Key为键的对象
例子:

Tab = ets:new(test_ets_new, [set, named_table]),
ets:insert(Tab, [{a, 1, 1}, {b, 2, 2}]),
ets:delete(Tab,c).
结果:true
为了确认是否已经删除我们可以执行ets:tab2list(Tab). 可以看到返回结果是 :[{b,2,2}] 说明确实已经删除了。

delete_all_objects(Tab) -> true
     Types:
          Tab = atom() | tid()
删除Tab中的所有对象,该操作会保持数据的原子性和独立性
delete_object(Tab, Object) -> true
删除与Object精确匹配的对象,只有键值相同,但其他有不匹配的对象不会被删除(这对于Bag类型的表非常有用,在duplicate_bag表中,所有匹配的对象都会被删除)。
例子1:

TableId = ets:new(test_ets_new, [named_table, bag]),
ets:insert(TableId, [{a, 1}, {b, 2}, {a, 3}, {c, 4}]),
ets:delete_object(TableId, {a, 3}),
ets:tab2list(TableId).
结果: [{c,4},{b,2},{a,1}]
例子2:

TableId = ets:new(test_ets_new, [named_table, duplicate_bag]),
ets:insert(TableId, [{a, 3}, {b, 2}, {a, 3}, {c, 4}]),
ets:delete_object(TableId, {a, 3}),
ets:tab2list(TableId).
结果:[{c,4},{b,2}]

修改/更新
update_element(Tab, Key, ElementSpec :: {Pos, Value}) -> boolean()
update_element(Tab, Key, ElementSpec :: [{Pos, Value}]) -> boolean()
更新ETS表Tab里键为Key的对象数据的第Pos个元素数据的值更改为Value。可一次更改一个键的多个Pos
Types:
                Tab = tid() | atom()
                Key = Value = term()
                Pos = integer()
例子:
Tab = ets:new(test_ets_new, [set, named_table]),
ets:insert(Tab, [{a, 1, 1}, {b, 2, 2}]),
ets:update_element(Tab, a, {2, 100}),
ets:tab2list(Tab).
结果:[{b,2,2},{a,100,1}]
一次修改多个位置:
Tab = ets:new(test_ets_new, [set, named_table]),
ets:insert(Tab, [{a, 1, 1}, {b, 2, 2}]),
ets:update_element(Tab, a, [{2, 100}, {3,10}]),
ets:tab2list(Tab).
结果:[{b,2,2},{a,100,10}]

查/查找
lookup(Tab, Key) -> [Object]
返回表Tab里键为Key的所有对象数据的列表
如果是ordered_set则键1.0 与 1相等。
例子1:

ets:new(test_ets_new, [set, named_table]),
ets:insert(test_ets_new, [{a, 1}, {b, 2}]),
ets:lookup(test_ets_new, a).
结果:[{a,1}]
例子2:

ets:new(test_ets_new, [ordered_set, named_table]),
ets:insert(test_ets_new, [{1, 1}, {2, 2}]),
ets:lookup(test_ets_new, 2.0).
结果:[{2,2}]
例子3:

TabId = ets:new(test_ets_new, [duplicate_bag, named_table]),
ets:insert(TabId, [{a, 1}, {b, 2}, {a, 3}]),
ets:lookup(TabId, a).
结果: [{a,1},{a,3}]

lookup_element(Tab, Key, Pos) -> Elem
如果表的类型是 set 或 ordered_set,那么该函数将返回键为 Key 的对象的第 Pos 个元素。
如果表的类型是 bag 或 duplicate_bag,那么该函数将返回键为 Key 的对象的第 Pos 个元素的列表。
如果表里没有键为 Key 的对象,函数将以 badarg 的原因退出。
例子1:set类型表

ets:new(test_ets_new, [set, named_table]),
ets:insert(test_ets_new, [{a, 1}, {b, 2}]),
ets:lookup_element(test_ets_new, a, 2).
结果:1
例子2:duplicate_bag类型表

ets:new(test_ets_new, [duplicate_bag, named_table]),
ets:insert(test_ets_new, [{a, 1}, {b, 2}, {a, 3}]),
ets:lookup_element(test_ets_new, a, 2).

结果:[1,3]

member(Tab, Key) -> true | false
判断表里是否存在指定键的数据
TableId = ets:new(test_ets_new, [named_table, set]),
ets:insert(TableId, [{a, 1}, {b, 2}, {c, 3}]),
ets:member(TableId, b).
结果:true

[作者:点A点C]
模式匹配相关函数(同样会有增删改查):

fun2ms(LiteralFun) -> MatchSpec
把语法函数转为匹配规范的伪函数
例子:
ets:fun2ms(fun({M, N}) when N > 3, is_atom(M) -> M end).
结果:[{{'$1','$2'},[{'>','$2',3},{is_atom,'$1'}],['$1']}]

查/匹配查找
select(Tab, MatchSpec) -> [Match]
使用一个匹配描述从表Tab中匹配对象。
MatchSpace是一个含有三个参数的元组元素: 第一个元素是ets:match/2的文档中描述的模式,第二个参数是含有多个断言测试的列表,第三个是包含关于实际返回值描述的列表。
简单来说  第一个参数是传入的已知变量,第二个参数是判断条件,第三个参数是返回结果。
返回值的结构使用 MatchHead 所绑定的 "match variables",或者使用特殊的匹配值 '$_'(整个匹配对象)和 '$$'(包含所有匹配值的列表)
Types:
          Tab = tid() | atom()
          Match = term()
          MatchSpec = match_spec()
例子1:返回值为‘$$’
Tab = ets:new(test_ets_new, [private]),
ets:insert(Tab, [{a, 1}, {b, 2}]),
ets:select(Tab, [{{'$1', '$2'}, [], ['$$']}]).
结果:[[b,2],[a,1]]

例子2:返回值为‘$_’

Tab = ets:new(test_ets_new, [private]),
ets:insert(Tab, [{a, 1}, {b, 2}]),
ets:select(Tab, [{{'$1', '$2'}, [], ['$_']}]).
结果:[{b,2},{a,1}]
例子3:返回MatchHead所绑定的“match variables”

Tab = ets:new(test_ets_new, [private]),
ets:insert(Tab, [{a, 1}, {b, 2}]),
ets:select(Tab, [{{'$1', '$2'}, [], ['$1']}]).
结果:[b,a]

例子4: 未弄明白为什么返回的是[2,1]

Tab = ets:new(test_ets_new, [private]),
ets:insert(Tab, [{a, 1}, {b, 2}]),
ets:select(Tab, [{{'$1', '$2'}, [], ['$1', '$2']}]).
结果:[2,1]


select(Tab, MatchSpec, Limit) -> {[Match], Continuation} | '$end_of_table'
用法和ets:select/2相似,只是返回限定数量(limit)的匹配对象数据。Continuation项可以在后续的ets:select/1调用中获取下一组匹配的对象数据。速度比ets:first/1 和ets:next/1逐个方位对象更快。
Types:
             Tab = tid() | atom()
             Match = term()
             MatchSpec = match_spec()
             Continuation = term()
select(Continuation) -> {[Match], Continuation} | '$end_of_table'
继续从ets:select/3开始的匹配,下一次匹配到的限定数量Limit的对象数据将与心得Continuation一起返回。心得Continuation 将会在后续调用该函数时被使用。
Types:
             Match = term()
             Continuation = term()


select_reverse(Tab, MatchSpec) -> [Match]
 ets:select/2 一样,都是根据匹配规范匹配表里的对象数据,不过如果是 ordered_set 类型的 ETS 表的话会返回一个倒序的列表,其他类型的表返回的值跟 ets:select/2 一样。
Types:
              Tab = tid() | atom()
              Match = term()
              MatchSpec = match_spec()
select_reverse(Tab, MatchSpec, Limit) -> {[Match], Continuation} | '$end_of_table'
与select_reverse/2的关系就像 selet/2 和selet/3的关系
Types:
                Tab = tid() | atom()
                Match = term()
                MatchSpec = match_spec()
                Continuation = term()
select_reverse(Continuation) ->{[Match], Continuation} | '$end_of_table'
Types:
                    Match = term()
                    Continuation = term()


删除
select_delete(Tab, MatchSpec) -> NumDeleted
根据匹配模式删除表里的对象数据
Types:
               Tab = tid() | atom()
               Object = tuple()
               MatchSpec = match_spec()
               NumMatched = integer()

不常用的匹配函数:
is_compiled_ms(Term) -> boolean()
检测一个 Erlang 数据是否是一个有效已编译的匹配规范

match(Continuation) -> {[Match], Continuation} | '$end_of_table'
match(Tab, Pattern) -> [Match]
根据匹配模式 Pattern 匹配 ETS 表 Tab 里的对象数据。
一个匹配模式也许包含的项值有:绑定部分(Erlang 项),'_' 可以匹配任何 Erlang 项,和匹配变量:'$N'(N>=0)
函数将返回一个匹配每个对象数据的元素的列表,每个元素是一个绑定变量模式的有序列表
Types:
    Tab = tid() | atom()
    Pattern = tuple()
    Match = [term()]
 
match(Tab, Pattern, Limit) -> {[Match], Continuation} | '$end_of_table'
参考select/2与
Types:
                        Tab = tid() | atom()
                        Pattern = tuple()
                        Match = [term()]
                        Continuation = term()
match_delete(Tab, Pattern) -> true
根据匹配模式删除表里的对象数据
Types:
    Tab = tab()
    Pattern = match_pattern()



一些不常用的函数:
all() -> [Tab]
返回当前节点中所有的ets表组成的列表。如果表有命名返回表名,否则返回表的标识符

i() -> ok
在输出端上打印显示所有的ETS表的信息、

i(Tab) -> ok
在输出端上打印显示指定ETS表Tab的信息
     Types:
          Tab = atom() | tid()

info(Tab) ->  [{Item, Value}] | undefined
返回一个以{Item, Value}元祖形式的列表的ETS表的信息。如果没有找到表则返回undefined,如果Tab不是一个表,则返回bagarg
Tab = tid() | atom()
               Item = atom(), see below
               Value = term(), see below

info(Tab, Item) -> Value | undefined
返回给出的跟表Tab相关的项Item的信息。如果没有找到表则返回undefined,如果Tab不是一个表或者Item是一个无效值,则返回bagarg

rename(Tab, Name) -> Name
给一个已命名的ETS表Tab重命名一个新的名字Name

first(Tab) -> Key | '$end_of_table'
返回ETS表Tab中的第一个对象数据的键     
例子:

ets:new(test_ets_new, [set, named_table]),
ets:insert(test_ets_new, [{a, 1}, {b, 2}]),
ets:first(test_ets_new).
结果:a

last(Tab) -> Key | '$end_of_table'
如果类型是 ordered_set,则返回 Erlang 项顺序的最后一个键将被返回;如果是其他类型的表,该函数的处理跟 ets:first/1 一样
ets:new(test_ets_new, [ordered_set, named_table]),
ets:insert(test_ets_new, [{a, 1}, {b, 2}]),
ets:last(test_ets_new).
结果:b

next(Tab, Key1) -> Key2 | '$end_of_table'
返回表里紧随键Key1的下一个键Key2.
除ordered_set之外的类型的表,如果有并发更新了表,遍历将失败,除非使用ets:safe_fixtable/2函数对表进行保护锁定。

prev(Tab, Key1) -> Key2 | '$end_of_table'
Types:
              Tab = tid() | atom()
              Key1 = Key2 = term()
返回在表里跟键 Key1 紧随的上一个键 Key2。如果是 ordered_set 类型的表,返回的是 Erlang 项顺序的前一个键将被返回;如果是其他类型的表,该函数的处理跟 ets:next/2 一样

foldl(Function, Acc0, Tab) -> Acc1
对ETS表数据进行循环遍历操作,规则和lists:foldl/3一样
     Types:
      Function = fun((Element :: term(), AccIn) -> AccOut)
             Tab = tab()
             Acc0 = Acc1 = AccIn = AccOut = term()
例子:

Tab = ets:new(ets_tab, [named_table, set]),
ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5}]),
ets:foldl(fun({_Key, Val}, AccVal) ->
    AccVal + Val
end, 0, Tab).
结果:15

foldr(Function, Acc0, Tab) -> Acc1
和ets:foldl/3一样,对ETS表进行遍历,区别是从表末端开始向前遍历
Types:

             Function = fun((Element :: term(), AccIn) -> AccOut)
            Tab = tab()
            Acc0 = Acc1 = AccIn = AccOut = term()
 例子:

Tab = ets:new(ets_tab, [named_table, set]),
ets:insert(Tab, [{a, 1}, {b, 2}, {c, 3}, {d, 4}, {e, 5}]),
ets:foldr(fun({_Key, Val}, AccVal) ->
    AccVal + Val
end, 0, Tab).
结果:15

一些很少用到的函数: 

safe_fixtable(Tab, Fix) -> true
Types:
     Tab = tid() | atom()
     Fix = boolean()
锁定一个类型是 set,bag 或 duplicate_bag 的表,使其可以安全遍历表里的数据

give_away(Tab, Pid, GiftData) -> true
让进程Pid成为表Tab的新的拥有者。
     Types:
        Tab = tid() | atom()
         Pid = pid()
         GiftData = term()

setopts(Tab, Opts) -> true
设置表的选项。目前可以在表创建后设置的选项只有heir,调用进程必须是表的所属进程。

update_counter(Tab, Key, X3 :: [UpdateOp], Default) -> [Result]
update_counter(Tab, Key, Incr) -> Result
update_counter(Tab, Key, Incr, Default) -> Result
更新ets中的数据,省去了从ets中“查找对象->更新对象数据->再插入新的对象”的过程
Types:
             Tab = tid() | atom()
             Key = term()
             UpdateOp = {Pos,Incr} | {Pos,Incr,Threshold,SetValue}
             Pos = Incr = Threshold = SetValue = Result = integer()

文件转换为tab
tab2file(Tab, Filename) -> ok | {error, Reason}
     Types:
          Tab = atom() | tid()
          Filename = file:name()
          Reason = term()
将Tab表导出道文件Filename,等同于table2file(Tab, Filename, [])
tab2file(Tab, Filename, Options) -> ok | {error, Reason}
     Types:
          Tab = atom() | tid()
          Filename = file:name()
          Options = [Option]
          Options = {extended_info, [ExtInfo]} | {sync, boolean()}
          ExtInfo = md5sum | object_count
          Reason = term()
将Tab表到处导文件Filename。导表时,一些关于表的必须的信息被导到头部,这些信息包括表的类型,名字,访问权限,大小,版本和是否是已命名表,同事还有关于教导文件中的一些扩展信息相关的注释,这些可以使文件中的对象数或者是头部和文件中record的MD5值。如果标的访问权限是public并且在导表的过程中有田间或删除的对象,头部的大小字段值可能与实际的对象数不一致。public权限的表在导表时有更新,并且想在从文件中读取表时核对,则扩展信息中至少要有一个字段给读取和核对进程提供依据。

扩展信息选项指出有哪些扩展信息被写到了文件中:
object_count
实际写入文件的对象数量写在了文件的尾部,因此即使在导表时有更新表,也可以核对。
md5sum
头部和表中的对象使用内建的MD5函数来校验.所有对象的MD5值写在文件的尾部,所以读取时的校验可以发现文件中的数据微小的比特级的反转。使用该选项将要耗费适量的CPU时间。
一旦使用了扩展信息选项,将导致ets版本早于stdlib-1.15.1的文件无法读取.

file2tab(Filename) -> {ok, Tab} | {error, Reason}
Types:
     Filename = file:name()
     Tab = tab()
     Reason = term()
读取一个由tab2file/2 或 tab2file/3生成的文件并创建对应的表,与file2tab(FileName, [])等效。
file2tab(Filename, Options) ->  {ok, Tab} | {error, Reason}
     Types:         
          Filename = file:name()
          Tab = atom() | tid()
          Options = [Option]
          Option = {verify,boolean()}
          Reason = term()
      读取一个由tab2file/2 或 tab2file/3生成的文件并创建对应的表。目前支持的选项只有{verify, boolean()}.如果检验打开(也就是设置为{verify, true}),该函数将利用文件中的所有信息来断定数据是否被损坏,实现方式依赖于调用tab2file/3时写入extended_info的信息。如果文件中没有extended_info数据,但却设置了{verify,true},写入对象的数量将依赖于转储时原始表的大小。
       如果在表是公共的并且在转储时有对象被删除或插入,将使得检验失败。为了避免这个问题,不要检验在转储的同时有更新的文件,或者在调用tab2file/3时使用{extended_info, [object_count]},这将会把实际写入的对象数记录到文件中。
       如果开启检验并且转储时使用{extended_info, [md5sum]}选项,在读取文件时将会比其他情况慢,消耗更多的CPU时间。
Options的默认值为{verify,false}.
tabfile_info(Filename) -> {ok, TableInfo} | {error, Reason}
返回通过tab2file/2或tab2file/3导入文件的标的信息






















阅读全文
0 0