Некоторое время назад страничка «Лучшие комментарии» была удалена с Хабра (подробности здесь: habrahabr.ru/qa/18401/).
Тем не менее, мне бывало интересно туда заглянуть — и ради лулзов, и статьи иногда интересные попадаются из тех, что в ленте упустил. Так что решил я сделать свой небольшой сервис. Надеюсь, администрация не будет против.
Первая «версия» выводила топ комментариев из последних N постов, была написана в LINQPad за два часа и занимала один экран (pastebin). Стало понятно, что «по запросу» это генерить нереально даже для постов за последние сутки (скорость загрузки 1-2 поста в секунду), а значит, надо сделать периодическое обновление. Отсюда пришла мысль крутить сервис на домашней машине (всегда включена) и загружать статичные результаты на бесплатный
Кратко о реализации
Код: code.google.com/p/habra-stats/
— Windows Service на C# (4.5, VS2012 — новые фичи не используются, можно собрать под 4.0)
— Парсинг на Regexp (и да, я знаю: You can't parse HTML with regex, но здесь сойдёт)
— MS SQL Express + Entity Framework (ну очень удобная ORM)
— XSLT для генерации HTML (вёрстку и css взял у хабра, да простит меня снова администрация)
Раз в два часа сервис просыпается, парсит страницу habrahabr.ru/posts/collective/new и получает Id самого нового поста, затем в обратном порядке загружает посты, пока дата публикации не достигнет порога (старше 3 дней). Посты парсятся и кладутся в базу.
Предварительно в базу были загружены все существующие посты (на это ушло двое суток).
Затем из базы генерятся «отчёты», такие как «лучшие за сутки», «худшие за месяц с картинкой» и т.п. Данные для отчёта — просто набор объектов «Comment», которые сериализуются и трансформируются XSLT. Результаты загружаются по FTP на
Для генерации отчётов и навигации между ними есть небольшая хитрость: каждый из фильтрующих методов (ЗаДень, ЗаНеделю, Лучшие, Худшие и т.д.) помечен атрибутом:
[CommentReport(Category = "Время" , Name = "За сутки" , CategoryOrder = 0)]
Через Reflection получаем все сочетания таких методов по категориям, получаем данные из базы и генерируем навигацию. Таким образом, чтобы добавить ещё один «отчёт» (например, «за три дня»), достаточно лишь добавить метод с атрибутом. Слава роботам LINQ и Entity Framework.
Немного о проблемах и решениях
Изначально думал обойтись без БД и делать всё как можно проще: хранить сырой HTML на диске, грузить в память и там обрабатывать. Но масштабы бедствия недооценил: 150 тысяч постов в HTML заняли 10 с лишним гигабайт. Даже на SSD время загрузки и парсинга неприемлемо.
Затем попробовал SQL Compact Edition (in-process база, поддерживает entity framework). Упёрся в лимит 4ГБ на размер файла базы. В тот момент была только одна таблица Comments с дублирующимися (денормализованными) данными. Уже после перехода на SQL Express частично убрал дублирование, добавив таблицу Posts, и удалил комментарии без голосов (которых было около 30%). В результате размер базы сейчас около 2ГБ.
В процессе парсинга узнал, что опрометчиво использованная RegexOptions.IgnoreCase снижает производительность в несколько раз.
Немного статистики
На момент написания статьи в базе:
90619 постов
18 комментариев к публикации в среднем (комментариев без голосов в базе нет)
15 из них с положительным рейтингом
1676593 комментария всего
721 комментарий в день
Среднее количество комментариев по дням недели
Комментариев в неделю: динамика по времени
Наконец, ссылки!
Сайт: habrastats.comyr.com (
Код ещё раз: code.google.com/p/habra-stats/
В планах
RSS с лучшими за предыдущие сутки
P.S. Предлагайте ещё интересные запросы
P.P.S. знаменитый комментарий к знаменитому топику про pornolab не отображается, так как автор публикации заблокирован.
Автор комментария nForce, увидеть комментарий можно здесь: habrahabr.ru/users/nforce/comments/page2/
Автор: kefirr