GrabDuck

GrabDuck: Как мы делаем статьи из закладок

:

Приветствуем тебя читатель. Не так давно на нашем сервисе GrabDuck появился новый парсер/экстрактор статей. Между собой мы называем его GrabDuck Article Extractor 2.0 или сокращенно GAE 2.0. Почему так громко? Дело в том, изменений и усовершенствований накопилось столько, что нам пришлось полностью выкинуть старый, с которым мы жили последние полтора года и создать новый парсер статей “с нуля”. И да, для нас это большое и важное изменение. Что нам не нравилось и что мы сделали в результате описано под катом.



Итак, мы долго жили со старым парсером, взятым со стороны в виде форка от какого-то open source проекта. Да, он был хорошим и старался выполнять свою работу на все 100 (где-то в одной из первых статей мы давали ссылку на него — если интересно, посмотрите). И для тех, чьи требования не превышают среднестатистических, мы по прежнему его рекомендуем к использованию — он точно справиться.

Но со временем все чаще стали натыкаться на различные ограничения. Сайты у нас, как известно, сохраняют всякие, до сих пор попадается ужасное наследие 2000х, когда и стандартов-то особых не было. Вообщем, тут наша библиотека давала сбой и приходилось все больше лезть в чужой код и править «под себя». Со временем, пожалуй основной претензией стало то, что библиотека была как швейцарский нож, хороша, но все делала сама: загружала документ по url, отслеживала редиректы, умела расшифровывать различные сокращатели ссылок, пыталась определить кодировку, даже если она не была явно задана, парсила документ, определяла изображения и даже пыталась понять дату, когда статья опубликована. Вообщем не библиотека, а сказка… Правда до тех пор, пока не требовалось что-то исправить или немного поменять. И мы часто стояли перед выбором: или править код напрямую, или, после обработки документа, проводить еще одну, свою собственную, естественно дублируя местами какую-то логику от нашего оригинального парсера. И решение это было непростым — создатель этой самой open source библиотеки явно не был фанатом тестирования и поэтому все работало ровно до момента пока не трогали и не вносили существенных изменений в код.

А учитывая, что сам процесс парсинга и извлечения статей, для тех, кто никогда с этим не сталкивался, полагается целиком на статистику, а не на четкие критерии, достаточно было чуть-чуть изменить веса применяемой статистической модели, и мы сразу рисковали, что однажды, какие-то классы сайтов просто перестанут обрабатываться корректно. Ведь общего формата-то нет — вся статья, это просто большой кусок html, в котором где-то внутри есть несколько параграфов так необходимого нам текста. Так что со временем у нас появился наш параллельный мир, когда уже обработанная и, казалось бы, уже подготовленная статья еще раз прогонялась, но уже через наш собственный недо-парсер.

Как эта open source библиотека работала в многопотоковом режиме была отдельная и очень грустная песня. И первоначально на больших импортах, когда счет шел на десятки тысяч закладок стоящих одновременно в очереди на обработку, все в нашем королевстве просто замирало.

И это был для нас урок номер 1: когда строите свою систему, используйте независимые компоненты — кирпичики. И именно из них собирайте то, что нужно вам. Если что-то пойдет не так, или появиться новый интересный проект, который выполняет работу лучше, всегда можно отключить старое и попробовать новое, не ломая систему и не рискуя, что все рассыпиться на каком-то этапе. А тут, уж поверьте нашему опыту, если что-то в мире чисел может пойти не так, оно обязательно пойдет не так и почти сразу.

Так что в конце мы решили — все, хватит, пора брать контроль в свои руки и писать что-то наше, под наши требования и с удовлетворяющем нас качеством. Так и появился на нашей архитектурной диаграмме новый компонент — GAE 2.0.
Прежде всего хотелось построить его в виде сборища независимых компонентов. Для каких-то шагов нам была нужна параллельная обработка по принципу, чем больше, тем лучше, где-то можно было обойтись и одним потоком, а где-то мы хотели ускориться распараллелив работу, но были серьезные ограничения на количество одновременно обрабатываемых элементов.

В результате вырисовывался этакий конвейер или pipeline, где каждая закладка превращается в полноценную статью, с каждым шагом наполняясь значимыми для пользователя данными.

Итак, какие же шаги нам необходимо предпринять, чтобы из ссылки сделать полноценную статью, которую уже можно показать пользователю?

После раздумий, зоны ответственности получились такие: Собственно сам Url Fetcher. Отвечает за непосредственную загрузку статьи по предоставленному Url. Должен понимать всевозможные редиректы, уметь работать через SSL и с сокращателями ссылок. И еще его нужно параллелить, ведь само ожидание ответа от сервера занимает годы компьютерного времени и с этим нужно что-то делать. Но и стратегия чем больше, тем лучше, тут тоже не подходит: будем бомбардировать один и тот же сайт запросами и нас попросту банально забанят. Значит нужен какой-то оптимум, что называется и нашим и вашим.

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

И только после этого наступает время для извлечения данных и подготовки финальной статьи, которую и будем показывать нашим пользователям. Что сюда входит? Получение мета-информации, а это заголовки, изображения, расчет тегов и языка документа. Конечно же нам необходим сам контент для полнотекстового поиска, также необходимо сгенерировать текстовый сниппет, кратко представляющий сам документ.

После этого документ готов к использованию и доступен для поиска на GrabDuck.

Итак новый парсер готов и ура все новые закладки уже пойдут через него и мы наконец-то получим, что хотели! Но большой вопрос, который может возникнуть у читателя: а что будет с существующими закладками? Ведь они были УЖЕ обработаны и УЖЕ сохранены в системе! Неужели они так и останутся нетронутыми? И наш ответ — нет! Прежде всего, у пользователя всегда есть возможность выбрать закладку и принудительно обновить ее. Для этого достаточно выбрать соответствующий пункт из контекстного меню. Выглядит это как то так.

Ну или просто подождать немного. Одна из замечательных особенностей GrabDuck состоит в том, что мы проводим периодическую проверку всех закладок: а все ли в порядке, живы ли до сих пор сайты, не появилось ли на странице новых комментариев и т.п. Так что рано или поздно, ваши закладки попадут на обновление и пройдут через GAE 2.0.

На сегодня это все, что мы хотели вам рассказать. Оставляйте свои комментарии и до встречи.