Топ комментариев Хабра — сервис, детали реализации, и немного статистики (С#)

от автора

Некоторое время назад страничка «Лучшие комментарии» была удалена с Хабра (подробности здесь: 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 (хостинг выбран первый попавшийся без рекламы с FTP)
Код ещё раз: code.google.com/p/habra-stats/

В планах

RSS с лучшими за предыдущие сутки

P.S. Предлагайте ещё интересные запросы

P.P.S. знаменитый комментарий к знаменитому топику про pornolab не отображается, так как автор публикации заблокирован.
Автор комментария nForce, увидеть комментарий можно здесь: habrahabr.ru/users/nforce/comments/page2/

ссылка на оригинал статьи http://habrahabr.ru/post/155541/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *