[Erlang]Тролльдетектор для rsdn
От: Mr.Cat  
Дата: 12.07.09 16:50
Оценка: 614 (36) +1 :))) :))) :))) :))) :))) :))) :))) :)))
Сегодня мы напишем детектор троллей для нашего форума. Почему в decl? Потому что на эрланге.
Обнаруживать троллей мы будем простым и эффективгым способом: будем строить граф интересующей нас ветки. Вершинами графа будут юзеры, а ребра (соответствующего веса и толщины) будут связывать тех юзеров, которые что-то друг другу писали. По такому графу нетрудно догадаться, кто есть кто в ветке.

Для вытягивания тем мы воспользуемся веб-сервисом rsdn (http://rsdn.ru/ws/janusAT.asmx). К сожалению, в wsdl сервиса (http://rsdn.ru/ws/janusAT.asmx?WSDL) значится левый порт (8888), поэтому wsdl мы сохраним на диск и уберем из него ошибочный порт, вот так: http://gist.github.com/145674.

В качестве soap-клиента будем использовать оный из yaws, про который можно прочитать пару строк здесь: http://yaws.hyber.org/soap_intro.yaws. Таким образом, из эрланговых либ нам понадобятся:
1. yaws
2. erlsom
3. ibrowse (к сожалению, веб-сервис не желает работать, когда в качестве http-клиента используется оный из http).
Из тулзов:
1. graphviz
2. imagemagick

Первым делом, сгенерируем hrl со структурами для веб-сервиса: http://gist.github.com/145677.
Далее напишем функцию, которая достанет все сообщения ветки по id этой самой ветки (вообще, сервис вроде бы достает ветку по id сообщения в ней, но id ветки совпадает с id первого сообщения в ней):
get_topic(Topic) ->
    ibrowse:start(),
    JanusWsdl = yaws_soap_lib:initModel("janusAT.wsdl"),
    {ok, _,
     [#'p:GetTopicByMessageResponse'{
       'GetTopicByMessageResult'=
       #'p:TopicResponse' {
         'Messages'=
         #'p:ArrayOfJanusMessageInfo'{'JanusMessageInfo' = Messages}}}]} =
    yaws_soap_lib:call(JanusWsdl, "GetTopicByMessage",
               [#'p:TopicRequest'{ userName = "username",
                           password = "password",
                           messageIds = #'p:ArrayOfInt'{int = [Topic]}}]),
    Messages.

Эта штука возвращает список структур 'p:JanusMessageInfo'. Далее, пользуясь тем, что веб-сервис отдает сообшения отсортированными по времени, посчитаем количество ответов, которые пользователи отправляли друг другу.
links(Messages)->
    links(Messages, dict:new(), dict:new()).
links([Message|Tail], UserDict, LinkDict) ->
    MessageId = Message#'p:JanusMessageInfo'.messageId,
    MessageNick = Message#'p:JanusMessageInfo'.userNick,
    NewUserDict = dict:store(MessageId, MessageNick, UserDict),
    ParentId = Message#'p:JanusMessageInfo'.parentId,
    case ParentId of
    0 -> links(Tail, NewUserDict, LinkDict);
    _ -> ParentNick = dict:fetch(ParentId, UserDict),
         links(Tail, NewUserDict,
            dict:update_counter(case MessageNick < ParentNick of
                        true -> {MessageNick, ParentNick};
                        false -> {ParentNick, MessageNick}
                    end, 1, LinkDict))
    end;
links([], _, LinkDict) ->
    dict:to_list(LinkDict).

Эта функция для некоторой гипотетической ветки возвращает список такого вот рода туплов:
[{{"DarkGray","eao197"},3},
 {{"Ikemefula","thesz"},2},
 {{"VGn","thesz"},4},
 {{"jazzer","lomeo"},1},
 {{"VladD2","thesz"},2},
 {{"DarkGray","thesz"},4},
 {{"StevenIvanov","thesz"},2},
 {{"Calabon","thesz"},1},
 {{"Ikemefula","eao197"},2},
 {{"eao197","thesz"},1},
 {{"Ikemefula","VladD2"},1},
 {{"jazzer","thesz"},10}]

Попрошу заметить, что все имена вымышленные и любые их совпадения с никами реальных людей случайны.
Теперь этот список преобразуем в граф для graphviz:
links2dot(Links) ->
    links2dot(Links, "}\n").
links2dot([{{Nick1, Nick2}, Weight}|Tail], Acc) ->
    links2dot(Tail, [io_lib:format("\"~s\" -- \"~s\" [weight=~B, label=~B, style=\"setlinewidth(~B)\"];\n", [Nick1, Nick2, Weight, Weight, linewidth(Weight)]) | Acc]);
links2dot([], Acc) ->
    lists:flatten(["graph Links {\noverlap=false;\n" | Acc]).

linewidth(Weight) ->
    if
    Weight < 3 -> 1;
    Weight < 10 -> 2;
    Weight < 50 -> 4;
    true -> 8
    end.

Этот граф остается записать в файл и сконвертить в картинку. Для выявления троллей, на мой взгляд, больше всего подходит neato. Для нашей гипотетической ветки мы получим вот такой граф:

Итак, наиболее вероятно, что в данной ветке троллем является thesz. Другие участники дискуссии практически не общаются друг с другом — только лишь с thesz-ом. Также заметно, что основным оппонентом thesz-а является jazzer. Но поскольку ему (кроме thesz-а) практически никто не отвечает — можно предположить, что jazzer представляет мнение большинства, тогда как thesz играет роль провокатора.

В качестве последнего штриха сделаем вот что. Будем строить несколько графов, представляющих состояния ветки в разные моменты времени. А потом сделаем gif.
link_progress(Topic) ->
    link_progress([links2dot(links(M)) || M <- heads(get_topic(Topic))], 0).
link_progress([Dot|Tail], N) ->
    file:write_file(lists:flatten(io_lib:format("~4.10.0B.dot", [N])), Dot),
    link_progress(Tail, N+1);
link_progress([], _) ->
    ok.

heads(List)->
    heads([], List).
heads([], [Head|Tail]) ->
    heads([[Head]], Tail);
heads([List|_]=Acc, [Head|Tail]) ->
    heads([[Head|List]|Acc], Tail);
heads(Acc, []) ->
    lists:reverse(lists:map(fun lists:reverse/1, Acc)).

Функция link_progress наполнит текущий каталог кучкой .dot файлов, которые мы сперва преобразуем в картинки:
for dot in *.dot; do neato -Tpng -o${dot}.png $dot; done

Потом первую (пустую) картинку заресайзим до размера, который должен быть у гифа. Вообще, это надо делать автоматически, а не вручную, но мне влом.
сonvert 0000.dot.png -resize 775x375\! 0000.dot.png

И теперь сделаем гиф из картинок с графами:
convert -delay 100 -loop 0 -dispose previous -dispose background *.png thread.gif

И получится у нас вот такая штука:

Такие дела. Как видите, мы написали очень полезную тулзу: она поможет модераторам более эффективно раздавать предупреждения, банить пользователей и применять другие меры наказания. Достаточно одного взгляда на граф "горячей" ветки, чтобы понять кто в ней троллит — и принять соответствующие меры. Ура, товарищи. Банхаммер, вперед!
Re: [Erlang]Тролльдетектор для rsdn
От: DemAS http://demas.me
Дата: 12.07.09 17:38
Оценка:
"Mr.Cat" <64543@users.rsdn.ru> writes:

> В качестве soap-клиента будем использовать оный из yaws, про который можно прочитать пару строк здесь: http://yaws.hyber.org/soap_intro.yaws. Таким образом, из эрланговых либ нам понадобятся:


А можешь посоветовать какую-либо статью/документацию по установке
библиотек в Erlang? То есть, есть ли здесь какой пакетный менеджер
аналогичный setuptools в python и gems в ruby? Или надо с каждой
библиотекой разбираться отдельно? Где надо располагать их файлы и как
прописывать к ним пути?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: [Erlang]Тролльдетектор для rsdn
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 17:57
Оценка: -1 :))) :)
Здравствуйте, DemAS, Вы писали:

DAS>"Mr.Cat" <64543@users.rsdn.ru> writes:


>> В качестве soap-клиента будем использовать оный из yaws, про который можно прочитать пару строк здесь: http://yaws.hyber.org/soap_intro.yaws. Таким образом, из эрланговых либ нам понадобятся:


DAS> А можешь посоветовать какую-либо статью/документацию по установке

DAS>библиотек в Erlang? То есть, есть ли здесь какой пакетный менеджер
DAS>аналогичный setuptools в python и gems в ruby? Или надо с каждой
DAS>библиотекой разбираться отдельно? Где надо располагать их файлы и как
DAS>прописывать к ним пути?

Cabal.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[3]: [Erlang]Тролльдетектор для rsdn
От: DemAS http://demas.me
Дата: 12.07.09 18:08
Оценка:
"thesz" <49985@users.rsdn.ru> writes:

> Cabal.


Замечательная штука, но при чем тут Haskell, если речь шла про Erlang?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Mr.Cat  
Дата: 12.07.09 18:13
Оценка:
Здравствуйте, DemAS, Вы писали:
DAS> А можешь посоветовать какую-либо статью/документацию по установке
DAS>библиотек в Erlang? То есть, есть ли здесь какой пакетный менеджер
DAS>аналогичный setuptools в python и gems в ruby? Или надо с каждой
DAS>библиотекой разбираться отдельно? Где надо располагать их файлы и как
DAS>прописывать к ним пути?

Пакетных менеджеров я, к сожалению, не знаю.
Про пути немного написано тут: http://erlang.org/doc/man/code.html, хотя немного запутано.
По-моему, самый надежный способ — скомпилировав либу, положить папку с ней () в code:lib_dir() таким вот образом:
|-- code:lib_dir()
    |-- library-version
        |-- ebin  <- *.beam идут сюда
        |-- include <- *.hrl идут сюда
        |-- src <- *.erl идут сюда

Что стоит учесть — изменения в этой папке не вступают в силу сами по себе во время выполнения.
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Курилка Россия http://kirya.narod.ru/
Дата: 12.07.09 18:25
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>"Mr.Cat" <64543@users.rsdn.ru> writes:


>> В качестве soap-клиента будем использовать оный из yaws, про который можно прочитать пару строк здесь: http://yaws.hyber.org/soap_intro.yaws. Таким образом, из эрланговых либ нам понадобятся:


DAS> А можешь посоветовать какую-либо статью/документацию по установке

DAS>библиотек в Erlang? То есть, есть ли здесь какой пакетный менеджер
DAS>аналогичный setuptools в python и gems в ruby? Или надо с каждой
DAS>библиотекой разбираться отдельно? Где надо располагать их файлы и как
DAS>прописывать к ним пути?

Есть CEAN, но это не setuptools/distutils.
Re: Злоупотребление тролльдетектором
От: Qbit86 Кипр
Дата: 12.07.09 18:26
Оценка: +3
Здравствуйте, Mr.Cat, Вы писали:

MC>Вершинами графа будут юзеры, а ребра (соответствующего веса и толщины) будут связывать тех юзеров, которые что-то друг другу писали.


Имхо, этот граф должен быть направленным. Иначе теоретически в «центре розы» может оказаться участник, который вообще не написал ни одного комментария. Пусть некие вымышленные VladD2, Ikemefula, eao197, DarkGray и jazzer (а ведь это может быть армия виртуалов одного и того же злоумышленника!) собрались скопом потроллить (т.н. «рейд») одного участника, скажем, thesz. Если они написали жертве каждый по 2 комментария, а jazzer — все десять, то получится картинка примерно похожая на первый гиф.

MC>Банхаммер, вперед!


Знавал я троллей, комменты которых были категорически интересней, чем у большинства участников атакуемой ветки. Иногда полезней зарыть не топор войны, а банхаммер. Чтоб формальный предлог применения оного не довлел над поиском истины, так сказать. Чтоб с водой не выплеснуть и ребёнка, чтоб за формой не потерять содержание, ну вы поняли.

MC>linewidth(Weight) -> ...


Было бы неплохо, если бы детектор ещё визуализировал толщину самого тролля :)
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: Злоупотребление тролльдетектором
От: Mr.Cat  
Дата: 12.07.09 19:07
Оценка:
Здравствуйте, Qbit86, Вы писали:
Q>Имхо, этот граф должен быть направленным. Иначе теоретически в «центре розы» может оказаться участник, который вообще не написал ни одного комментария. Пусть некие вымышленные VladD2, Ikemefula, eao197, DarkGray и jazzer (а ведь это может быть армия виртуалов одного и того же злоумышленника!) собрались скопом потроллить (т.н. «рейд») одного участника, скажем, thesz. Если они написали жертве каждый по 2 комментария, а jazzer — все десять, то получится картинка примерно похожая на первый гиф.

Оптимальная форма представления — это, конечно, открытый вопрос. Помнится, примерно таким графом ктото на канале #scheme визуализировал дискуссии — и мне он показался довольно неплохим по соотношению простота реализации/выразительность.

Например, можно рисовать ребро с суммой сообщений, если юзеры пишут друг другу примерно в равных количествах, и дуги, если кто-то пишет больше. Как-то так:
Re[4]: [Erlang]Тролльдетектор для rsdn
От: Rtveliashvili Denys Великобритания  
Дата: 12.07.09 19:09
Оценка: 1 (1) +1
DAS> Замечательная штука, но при чем тут Haskell, если речь шла про Erlang?

Смотрите начало треда до полного просветления.
Re: [Erlang]Тролльдетектор для rsdn
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 12.07.09 19:39
Оценка:
Здравствуйте, Mr.Cat, Вы писали:


MC>Итак, наиболее вероятно, что в данной ветке троллем является thesz. Другие участники дискуссии практически не общаются друг с другом — только лишь с thesz-ом. Также заметно, что основным оппонентом thesz-а является jazzer. Но поскольку ему (кроме thesz-а) практически никто не отвечает — можно предположить, что jazzer представляет мнение большинства, тогда как thesz играет роль провокатора.


А может быть и иначе — thesz отвечает на вопросы контингента а jazzer пытается на него наскакивать.

Вообще в любой дискуссии, мало-мальски занятной, будь то в интернет, будь то в реальной жизни, никогда не бывает такой ситуации, когда все общаются со всеми.

Практически всегда выделяются фракции в зависимости от взглядов, интересов, возраста, опыта и тд и тд.

И одна из фракций будет обязательно в центре.
Re: [Erlang]Тролльдетектор для rsdn
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 12.07.09 19:57
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Сегодня мы напишем детектор троллей для нашего форума. Почему в decl? Потому что на эрланге.


А можно как нибудь сложить это все в одну пачку, что взял да запустил одним кликом ?
Re[4]: [Erlang]Тролльдетектор для rsdn
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 20:58
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>"thesz" <49985@users.rsdn.ru> writes:


>> Cabal.


DAS> Замечательная штука, но при чем тут Haskell, если речь шла про Erlang?


http://rsdn.ru/forum/decl/3372042.1.aspx
Автор: thesz
Дата: 25.04.09
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re: [Erlang]Тролльдетектор для rsdn
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 21:08
Оценка: :)
Здравствуйте, Mr.Cat, Вы писали:

MC>Сегодня мы напишем детектор троллей для нашего форума. Почему в decl? Потому что на эрланге.


Из-за сбившегося форматирования (текст много шире окна просмотра) я не прочитал основной комментарий, а читал только комментарии поменьше.

Что делает моё поведение ещё более забавным.

PS
(к главным по RSDN)
А нельзя ли сделать так, чтобы текст пояснение не вылезал за пределы окна просмотра вне зависимости, вылезает ли код примеров? А то жутко неудобно читать.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re: [Erlang]Тролльдетектор для rsdn
От: Qbit86 Кипр
Дата: 12.07.09 21:52
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

MC>Сегодня мы напишем детектор троллей для нашего форума.


Троллефоб детектед? ;)
Глаза у меня добрые, но рубашка — смирительная!
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Odobenus Rosmarus  
Дата: 12.07.09 21:55
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>"Mr.Cat" <64543@users.rsdn.ru> writes:


>> В качестве soap-клиента будем использовать оный из yaws, про который можно прочитать пару строк здесь: http://yaws.hyber.org/soap_intro.yaws. Таким образом, из эрланговых либ нам понадобятся:


DAS> А можешь посоветовать какую-либо статью/документацию по установке

DAS>библиотек в Erlang? То есть, есть ли здесь какой пакетный менеджер
DAS>аналогичный setuptools в python и gems в ruby? Или надо с каждой
DAS>библиотекой разбираться отдельно? Где надо располагать их файлы и как
DAS>прописывать к ним пути?

faxien/sinan http://code.google.com/p/sinan/ http://code.google.com/p/faxien/
--
Odobenus Rosmarus, hochpersonlich
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Mr.Cat  
Дата: 12.07.09 22:29
Оценка:
Здравствуйте, Qbit86, Вы писали:
Q>http://lurkmore.ru/
А вот между прочем, на люрке нет статьи про рсдн.
Re[2]: [Erlang]Тролльдетектор для rsdn
От: geniepro http://geniepro.livejournal.com/
Дата: 13.07.09 05:22
Оценка:
Здравствуйте, thesz, Вы писали:

T>А нельзя ли сделать так, чтобы текст пояснение не вылезал за пределы окна просмотра вне зависимости, вылезает ли код примеров? А то жутко неудобно читать.


Опера бы Вам помогла тут...
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Mr.Cat  
Дата: 13.07.09 10:37
Оценка:
Здравствуйте, Ikemefula, Вы писали:
I>А можно как нибудь сложить это все в одну пачку, что взял да запустил одним кликом ?
Охх, этого я пока не предусмотрел... Если выдастся свободное время — могу попробовать собрать все вместе... Там вон, гляжу, про билдсистемы/пакетные менеджеры подсказывают.
Re[2]: [Erlang]Тролльдетектор для rsdn
От: Mr.Cat  
Дата: 13.07.09 10:42
Оценка:
Здравствуйте, Ikemefula, Вы писали:
I>А может быть и иначе — thesz отвечает на вопросы контингента а jazzer пытается на него наскакивать.
I>Вообще в любой дискуссии, мало-мальски занятной, будь то в интернет, будь то в реальной жизни, никогда не бывает такой ситуации, когда все общаются со всеми.
I>Практически всегда выделяются фракции в зависимости от взглядов, интересов, возраста, опыта и тд и тд.
I>И одна из фракций будет обязательно в центре.

Ну так я и не претендовал на достоверность.
Все-таки автоматическое распознавание троллей — это тянет на тему для диссертации по какой-нибудь социологии.
Re[3]: [Erlang]Тролльдетектор для rsdn
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 13.07.09 11:12
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

I>>Практически всегда выделяются фракции в зависимости от взглядов, интересов, возраста, опыта и тд и тд.

I>>И одна из фракций будет обязательно в центре.

MC>Ну так я и не претендовал на достоверность.

MC>Все-таки автоматическое распознавание троллей — это тянет на тему для диссертации по какой-нибудь социологии.

Тролль это очень мутное понятие, неясно что в себя включает.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.