kika: (Default)
kika ([personal profile] kika) wrote2009-12-21 09:29 am
Entry tags:

Purely functional data something

Имхо, довольно распространенная задача. Скажем у нас есть множество структур, описывающих некую жызненную ситуацию, скажем мониторинг хостов в сети. Структура содержит имя хоста, адрес, всякие прочие фактически иммутабельные параметры плюс некое количество изменяющихся параметров мониторинга, время пинга, скорость передачи данных, количество HTTP ошибок и теде и тепе. Структуры хранятся, допустим для простоты, в хеше по имени хоста. Все отлично, софтина работает, обмеряет хосты, апдейтит табличку с записями и жизнь прекрасна. Теперь нам надо сделать запросы снаружи - типа а покажи-ка мне список хостов, отсортированных по пингу. Допустим, хостов у нас ровно один газиллион, поэтому сортировать на каждый запрос накладно.
В традиционной культуре мы строим сбалансированные деревья с указателями на структуры (а в структурах указатели на деревья) и организуем синхронное плавание.
А как в функциональной культуре решается такая задача? Pointer trickery тут какбе немного недоступна.

Вкратце: есть структура -record(host, {host_id, speed = 0}). и из нее ETS таблица из одного газиллиона записей. Надо быстро отдавать список хостов, отсортированный по speed. Можно наверное положить это в Мнезию и понадеяться на ее ORDER BY, а если без Мнезии, ручками?

[identity profile] kika.livejournal.com 2009-12-21 12:46 pm (UTC)(link)
что делает transform/2 ? Обходит все дерево и прикладывает к каждой ноде fun?

[identity profile] lionet.livejournal.com 2009-12-21 12:50 pm (UTC)(link)
Вызывает двоичный поиск по ключу (ключ забыл явно вторым аргументом указать). O(logN). Когда найдёт ключ, то вызывает функцию, и осуществляет операцию, которая этой функцией была подсказана, и либо оставляет дерево в покое, либо трансформирует текущую ноду.

[identity profile] kika.livejournal.com 2009-12-21 02:17 pm (UTC)(link)
А ключом у тебя в дереве является скорость? А то что половина хостов имеют скорость 0, никому не помешает?

[identity profile] lionet.livejournal.com 2009-12-21 02:34 pm (UTC)(link)
А в чём дело? Если они просто её "имеют" — то дерево не перестраивается и даже не читается, так как срабатывает short-cirquit в псевдокоде, первой же строчкой.

А если значения флуктуируют в очень небольшом промежутке, тогда всё зависит от способа организации этого bag'а: есть ли в нём возможность указать secondary key. В простейшем случае можно сделать двухуровневый set: на первом уровне ключём является скорость, на втором - хост. Экстраполируя, получаем API для бэгов произвольной глубины:
transform(MultiBag, Keys, TransF) -> Result
Types   MultiBag = gb_trees()
       Keys = [term()]
       TransF = fun(Entry) -> retain | {replace, Entry} | delete


Пример:
transform(…, [0, "localhost"], fun({0, "localhost", _Key}) -> retain end).

[identity profile] kika.livejournal.com 2009-12-21 03:22 pm (UTC)(link)
Флуктуируют они в адском промежутке, конкретно скорость может колебаться от нуля до wire speed. Но идею я понял, спасибо.

[identity profile] lionet.livejournal.com 2009-12-21 03:26 pm (UTC)(link)
А если значения флуктуируют в очень небольшом промежутке

Фигню сморозил, конечно, очередной раз. Флуктуировать они могут как угодно, тут от степени флуктуации ничего не зависит.

[identity profile] kika.livejournal.com 2009-12-21 03:54 pm (UTC)(link)
Тут на самом деле неприятнее то, что надо знать OldSpeed, который можно выудить только еще одним лукапом. Но это терпимый оверхед.

[identity profile] lionet.livejournal.com 2009-12-21 03:59 pm (UTC)(link)
O(logN), он и в африке O(logN), даже с большой константой. А учитывая то, что при использовании эрланга ты уже получаешь фактор ~3-10x от скорости C, плюс-минус два в середине очень короткого цикла не должно волновать ;)

[identity profile] kika.livejournal.com 2009-12-21 04:02 pm (UTC)(link)
Ктоб ерлангу хороший компилятор написал...