Gitfm.com – сервис персональных рекомендаций Github репозиториев на основе коллаборативной фильтрации starred репозиториев пользователя.
Под катом описание архитектуры и двухдневная хроника, т.к. проект был создан с нуля за 48 часов в рамках конкурса RailsRumble2012.
Пятница, вечер
Пару дней назад мы с коллегами из Evrone приняли решение, что будем участвовать в RailsRumble2012. Суть конкурса простая – на команду из 4ох человек выдается один приватный репозиторий в Github и один
Выбирали идею классическим брейнштормом – в Campfire (т.к. мы все живем в разных городах – Минск, Москва, Прага и Хельсинки) по очереди выставляли идеи и по 30 секунд каждый писал, что о ней думает. В итоге, отказавшись от трекера полезных дел, агрегатора отзывов о товарах и еще пары совсем стартаперских идей мы сошлись на Gitfm.
Суббота, очень раннее утро
Мы уже во всю обсуждали архитектуру приложения. Не буду вдаваться в подробности, вот результат:
Rails app
Основное приложение написано на Ruby on Rails. Из особенностей могу указать, что для быстрого скачивания пользовательских данных мы используем EM Synchrony, для управления генерацией рекомендаций используем Resque. Возможность отмечать репозитории как starred в Github с нашего сайта реализуется с помощью гема octokit. Мы написали в Github и попросили увеличить лимит API запросов для нашего приложения – через несколько часов нам ответили и увеличили квоту до 300 000 запросов в день.
Я очень советую использовать EM Synchrony для сбора данных, кроулинга, вот несколько отличных примеров использования:
gistflow.com/posts/213-check-pages-status-with-em-synchrony-crawler
stackoverflow.com/questions/11000029/nested-iterators-for-em-synchrony-in-ruby
Воскресенье, полдень
jRuby демон и рекомендации
Rails приложение по запросу рекомендаций кладет id пользователя в специальную Redis очередь, из которой демон по очереди их вытаскивает и обрабатывает. Демон написан на jRuby потому что мы используем в качестве рекомендательного движка Apache Mahout, т.е. используем алгоритмы коллаборативной фильтрации. В качестве меры близости мы взяли коэффициенты Танимото, для оценки репозиториев мы используем бинарные данные, т.е. по сути наши пользователи ставят оценки 0 или 1. В будущем, естественно, мы будем учитывать watched репозитории, форки, частоту обновления репозитория. За 2 дня лично я открыл для себя просто новый мир, настолько интересной мне кажется эта область. С удовольствием делюсь с вами полезными ссылками по теме:
habrahabr.ru/post/150399/
www.igvita.com/2007/01/15/svd-recommendation-system-in-ruby/
www.igvita.com/2009/09/01/collaborative-filtering-with-ensembles/
jaydonnell.com/blog/2011/10/21/collaborative-filtering-using-jruby-and-mahout/
code.google.com/p/unresyst/wiki/CreateMahoutRecommender
Воскресенье, ночь, несколько часов до окончания конкурса
WebSocket сервер
Для передачи данных между приложениями мы использовали редис. Для отправки сообщения о завершении создания рекомендаций был написан специальный сервер – клиент в браузере заходит на страницу и мы открывает подключение к нашему серверу, который слушает каналы редиса по паттерну «messages:*» и хранит связи id — connections. То есть воркеру достаточно послать сообщение на «messages:#{user_id}» и оно дойдет через сокет-сервер до клиента в браузер. Подробнее можно почитать тут:
github.com/igrigorik/em-websocket
github.com/mloughran/em-hiredis
github.com/gimite/web-socket-js
Заключение
На данный момент в нашей базе 2413 пользователей, из них 1070 зарегистрировались сегодня, 84762 репозитория, обработано 2789 запросов на рекомендации.
В планах у нас – отойти от бинарной модели рекомендаций, сделать возможность убрать репозитории из списка рекомендованных, развернуть отдельный сервер для генерации рекомендаций (сейчас ничего нельзя трогать в проекте, пока его не оценило жюри).
На последок вариант октокэта, нарисованный тоже в рамках RailsRumble специально для GitFM:
Над проектом работали makaroni4, releu, ognevsky и kirs из компании Evrone.
Автор: makaroni4