каков идиоматический способ ограничения количества записей под определенным ключом в мнезии? - PullRequest
4 голосов
/ 10 ноября 2011

Я использую mnesia для хранения данных для пользователей, а запись представляет собой пакет, структурированный как

{username, field1, filed2, timestamp}

Чтобы база данных не взорвалась,Я хочу установить ограничение на количество записей, принадлежащих определенному пользователю, скажем, если количество записей для пользователя достигает 500, то запись с самой старой отметкой времени удаляется перед вставкой новой записи.

Есть ли эффективный способ сделать это?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 11 декабря 2011

Другим способом может быть запись вашей записи

{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, который вы ... Игнорируете.

Ваша торговля в режиме постоянного поискана ваш ключ для некоторых манипуляций со списком, но может быть хорошим компромиссом в зависимости от вашего приложения.Вы также можете избавиться от поля метки времени и связанного с ним кода, чтобы поддерживать это поле.

0 голосов
/ 10 ноября 2011

Я предоставил две возможности. Тот, который вписывается в ваш дизайн, и тот, который вносит небольшое изменение в определение вашей записи. Посмотрите, какой из них лучше всего соответствует вашим потребностям. Первый ниже работает в вашем дизайне.

-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 в транзакции не является оптимальной. Давайте подумаем о лучшем пути. Кроме того, я не знаю, как выглядят ваши временные метки, поэтому я уверен, что у вас есть способ отсортировать их и узнать последнюю временную метку, выбрать запись, которой принадлежит эта временная метка, а затем вернуть ее. Я дал это решение просто для вашего дизайна. Я также думаю, что некоторые, где нам нужно немного indexing. Следующая реализация кажется мне лучше. Например, если мы можем изменить определение записи, и мы вводим поле oldest, которое принимает bool(), и мы индексируем его следующим образом

-record(user,{
            username,
            field1,
            field2,
            timestamp,
            oldest      %% bool(), indexed<br>      }).<br>
insert_user(Username,Field1,Field2)->
    User = #user{
                username = Username,
                field1 = Field1,
                field2 = Field2,
                timestamp = {date(),time()}<br>
                }.
    insert(User).<br>
%% execute this within a mnesia transaction<br>
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.
Вышеприведенная реализация кажется мне лучше. успех !!
...