在 mnesia 中限制某个键下的记录数量的惯用方法是什么?

发布于 2024-12-14 22:32:40 字数 220 浏览 3 评论 0原文

我使用mnesia为用户存储数据,记录是一个包,结构如下

{ username, field1, filed2, timestamp }

为了不让数据库爆炸,我想对属于某个用户的记录数设置一个限制,比如说,如果记录数如果用户达到 500,则在插入新记录之前删除具有最早时间戳的记录。

有没有有效的方法来做到这一点?

提前致谢。

I use mnesia to store data for users, and the record is a bag structured like

{ username, field1, filed2, timestamp }

In order not to let the database explode, I want to set a limit for the number of records belonging to a certain user, say, if the number of records for a user reaches 500, then the record with the oldest timestamp is deleted before a new record is inserted.

Is there an efficient way to do this?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北风几吹夏 2024-12-21 22:32:40

另一种方法可能是让您的记录位于

{username, value_list, timestamp} 

value_list 包含值列表的位置。 可以执行此类操作

{NewList,_ignore}=lists:Split(500, [{NewFld1,NewFld2}|Value_list]),
%mnesia:write(Rec#{value_list=NewList}) type of code goes next

现在,您的桌子可以是一套而不是袋子,并且无论何时插入都 。 NewList 将最多包含 500 个元素,并且由于最旧的元素位于末尾,因此如果您有 501 个元素,最后一个元素将位于 _ignore 列表中,您将...忽略。

您可以在密钥上进行恒定时间查找以进行某些列表操作,但这可能是一个很好的权衡,具体取决于您的应用程序。您还可以摆脱时间戳字段和关联的代码来维护该字段。

Another way might be to have your record be

{username, value_list, timestamp} 

where value_list contains a list of values. Your table can now be a set instead of a bag and you can do this type of thing

{NewList,_ignore}=lists:Split(500, [{NewFld1,NewFld2}|Value_list]),
%mnesia:write(Rec#{value_list=NewList}) type of code goes next

whenever you insert. NewList will contain at most 500 elements and since the oldest elements are on the end, if you have 501 elements the last will be in the _ignore list which you will... Ignore.

Your trading a constant time lookup on your key for some list manipulation, but might be a good trade-off depending on your application. You also may be able to get rid of the timestamp field and associated code to maintain that field.

千柳 2024-12-21 22:32:40

我提供了两种可能性。一种适合您的设计,另一种对您的记录定义进行微小的更改。查看哪一款最适合您的需求。下面的第一个在您的设计中工作。

-record(user,{username,field1,field2,timestamp}).

%% execute the function below in a mnesia transaction

insert(#user{username = U,timestamp = _T} = User)->
    case mnesia:read({user,U}) of
        [] -> mnesia:write(User);
        AllHere -> 
            case length(AllHere) == 500 of
                false -> %% not yet 500
                      mnesia:write(User);
                true -> 
                    %% value has reached 500
                    %% get all timestamps and get the 
                    %% oldest record and delete it
                    %% 
                    OldRecord = get_oldest_stamp(AllHere),
                    ok = mnesia:delete_object(Record),
                    mnesia:write(User)
            end
    end.

get_oldest_stamp(UserRecords)-> 
    %% here you do your sorting
    %% and return the record with
    %% oldest timestamp
    ....
    OldRecord.


交易中的 length/1 函数并不是最优的。让我们想一个更好的办法。另外,我不知道你的时间戳是什么样子,所以我确信你有办法对它们进行排序并找出最新的时间戳,选出拥有该时间戳的记录,然后返回它。我给出这个解决方案只是为了适合您的设计。我还认为有些地方我们需要一些索引。下一个实施对我来说似乎更好。如果我们可以更改记录定义并引入一个采用 bool() 的字段 oldest 并像这样对其进行索引,会怎么样

-record(user,{
            username,
            field1,
            field2,
            timestamp,
            oldest      %% bool(), indexed
}).
insert_user(Username,Field1,Field2)-> User = #user{ username = Username, field1 = Field1, field2 = Field2, timestamp = {date(),time()}
}. insert(User).
%% execute this within a mnesia transaction
insert(#user{username = U} = User)-> case mnesia:read({user,U}) of [] -> mnesia:write(User#user{oldest = true}); AllHere -> case length(AllHere) == 500 of false -> %% unset all existing records' oldest field %% to false F = fun(UserX)-> ok = mnesia:delete_object(UserX), ok = mnesia:write(UserX#user{oldest = false}) end, [F(XX) || XX <- AllHere], ok = mnesia:write(User#user{oldest = true}); true -> [OldestRec] = mnesia:index_read(user,true,oldest), ok = mnesia:delete_object(OldestRec), ok = mnesia:write(User#user{oldest = true}) end end.

The above implementation seems better to me. success !!

I have provided two possibilities. One that fits within your design and one that introduces a small change in your record definition. See which one best fits your needs. The first one below is working within your design.

-record(user,{username,field1,field2,timestamp}).

%% execute the function below in a mnesia transaction

insert(#user{username = U,timestamp = _T} = User)->
    case mnesia:read({user,U}) of
        [] -> mnesia:write(User);
        AllHere -> 
            case length(AllHere) == 500 of
                false -> %% not yet 500
                      mnesia:write(User);
                true -> 
                    %% value has reached 500
                    %% get all timestamps and get the 
                    %% oldest record and delete it
                    %% 
                    OldRecord = get_oldest_stamp(AllHere),
                    ok = mnesia:delete_object(Record),
                    mnesia:write(User)
            end
    end.

get_oldest_stamp(UserRecords)-> 
    %% here you do your sorting
    %% and return the record with
    %% oldest timestamp
    ....
    OldRecord.


The length/1 function within the transaction is not optimal. Lets think of a better way. Also, i do not know how your timestamps look like so am sure you have a way of sorting them and finding out the latest timestamp, pick out the record which owns this timestamp and then return it. I have given this solution just to fit your design. I also think the some where we need some indexing. The next implementation seems better to me. Some how if we can change the record definition and we introduce a field oldestwhich takes a bool() and we index it like this

-record(user,{
            username,
            field1,
            field2,
            timestamp,
            oldest      %% bool(), indexed
}).
insert_user(Username,Field1,Field2)-> User = #user{ username = Username, field1 = Field1, field2 = Field2, timestamp = {date(),time()}
}. insert(User).
%% execute this within a mnesia transaction
insert(#user{username = U} = User)-> case mnesia:read({user,U}) of [] -> mnesia:write(User#user{oldest = true}); AllHere -> case length(AllHere) == 500 of false -> %% unset all existing records' oldest field %% to false F = fun(UserX)-> ok = mnesia:delete_object(UserX), ok = mnesia:write(UserX#user{oldest = false}) end, [F(XX) || XX <- AllHere], ok = mnesia:write(User#user{oldest = true}); true -> [OldestRec] = mnesia:index_read(user,true,oldest), ok = mnesia:delete_object(OldestRec), ok = mnesia:write(User#user{oldest = true}) end end.

The above implementation seems better to me. success !!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文