Bookradar — итоги 2015 года

Сейчас на Букрадаре обновляются данные по 27 магазинам.

За этот год отвалились e5.ru — закрылся, Читай-Город — по старому адресу выгрузки нет, а на почту не отвечают, а также combook.ru и regionbook.ru — не знаю причину.

Несколько магазинов подключились, например Книгосвет, остальные уже и не помню.

Кроме подключения нескольких магазинов я фактически ничего с сайтом не делал.

Начинался год ни шатко ни валко, в среднем как-то окупался хостинг (16.72 евро). К лету ситуацию ухудшилась, хотя трафик просел не так уж сильно, количество заказов уменьшилось в несколько раз. Мысль что я плачу за хостинг, а сайт даже не окупается меня не радовала. Даже подумывал отключить его, но мысль, то что реально люди им пользуются не давала мне это сделать. В какой-то момент я все-таки не оплатил хостинг. После того как сайт отключили, незнакомые люди начали писать Вконтакте, спрашивать, что с сайтом. Пришлось включить обратно)

В сентябре попер трафик. Я думал, что это связано с началом учебного года. В том году была похожая ситуация, и в октябре трафие просел обратно. В этот раз было не так. Трафик уже не опустился к прежним значениям.

Сколько в итоге заработано

  • labirint.ru 10969 руб (во второй половине они сильно урезали проценты, так что сейчас там совсем мало капает)
  • my-shop 10479 руб
  • ozon.ru 7137 руб
  • bookvoed.ru 2692 руб
  • books.ru 1500 руб

У остальных магазинов либо нет партнерских программ, либо там сложно получить информацию по статистике и там совсем крохи.

Итого за год получилось 32777 руб. Затраты на хостинг примерно 15 тыс, точно сказать сложно, т.к. хостинг в евро, а курс сильно колебался. Т.е. я даже что-то заработал. Это приятно)

Заявку в Adsense мне не одобрили, зато с таким трафиком уже можно было пробовать подключится к РСЯ, что я и сделал. Договор получил, но рекламу пока размещать не стал. Я вообще-то воткнул рекламный блок, но там что-то сглючило с AJAX-запросами, разбираться не стал, рекламу отключил. Ради пары баксов в месяц разбираться было лень.

Что касается Яндекс.Маркета, то как минимум на части запросов Букрадар сейчас впереди. Например по запросу «Путь камикадзе» он находит 7 предложений, а маркет только одно.

Приложение для андройда (сделал его в сентябре 2014 года). Установок всего 135, активных 41. Я его никак не продвигал, кроме как писал пост у себя в блоге. Сам пользуюсь, когда захожу в книжный магазин. Мне нравится. Самая удобная штука — сканировать штрихкод (EAN13 / ISBN).

В 2016 хочу на сайте сделать раздел «Избранное», куда пользователи могут добавлять книги, и дать возможность их тегировать, а также расширенный поиск, с кучей фильтров (по цене, магазинам, издательствам, сериям, авторам). Правда сейчас мне сложно выделить время на что либо.

 

 

 

Яндекс Книга

yandex-kniga Дочитал на досуге еще одну книгу —  Дмитрий Соколов-Митрич «Яндекс.Книга»

Она валалась уже несколько месяцев на полке вместе с книгой «Яндекс Воложа» (до нее пока не добрался).  Посмотрел по рейтингам на Озоне, у этой рейтинг получше. Отзывы конечно часто бывают накурченные, да и просто все люди разные, так что много хороших отзывов еще ни о чем не говорит. Все таки решил начать с нее.

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

Первые несколько страниц были достаточно скучные. Дальше стало гораздо интереснее. Много глав прочитал на одном дыхании, с трудом удавалось оторватсья и заставить себя пойти спать. Бывыли конечно и скучные места.

Книга описывает историю Яндекса от рождения Аркадия Воложа и Ильи Сегаловича до февраля 2014 года. Она достаточно свежая и это жирный плюс.

В книге не только про Яндекс.  В главах содержатся интервью с разными людьми известными российскими IT-предпринимателями. Я правда так до конца и не понял по какому принципу отбирали этих людей и имеют ли они какое-то отношение к Яндексу. Однако читать их было не менее интересно, чем основную линию.

Книга описывает прошлое компании — как появилась комапния, кто ее финансировал, как  и почему запускались разные сервисы — директ, маркет, народ и прочие. Описывает идеалы компании, видение ее создателей, и отчасти ее будущее. Например зачем Яндекс полез в Турцию, или про новое направление про обработку больших данных для коммерческого применения, как услуга для других компаний. Историй тут явно не меньше, чем в книге «Стартап в сети» Дэвида Коэна

Рекомендую к прочтению всем кому интересны истории создания успешних компаний. Практическая ценность таких книг конечно спорная (смотри ошибку выжившего), но читать их порой поинтереснее, чем закрученный детектив.

Если вдруг издатели «Манн, Иванов и Фербер» прочтут мой отзыв, скажу пару слов про оформление. Обложка твердая — бумага белая, хорошая. Но блин, зачем делать такие большие поля?! Если хотите сделать размер побольше, то увеличьте шрифт, читать будет легче. Или обрежте по этим полям — размер книги будет меньше, удобнее положить в сумку. Очень было бы круто добавить фотографии. Во-первых для всех важных людей которые встречаются в книге, а во-вторых можно много всяких интересных фоток найти — офисов, интерфейсов, команд. Для данной книги это было бы огромный плюс.

 

 

 

Программист фанатик — на редкость крутая книга!

1011960574

Чед Фаулер «Программист-фанатик»

Я особо не знал что ждать от этой книги, думал там что-то про то, как писать крутой код или взаимодействовать к команде. Может быть что-то похожее на книгу «Программист прагматик»

Да и после унылой «Remote. Офис не обязателен» Фрайда, как-то не ожидал увидеть что-то новое и интересное.

Книга начинается достаточно интересно, но через несколько десятков страниц стало скучновато, и я уже думал, что все — дальше будет еще хуже. Как это обычно бывает, автор выкладывает свою мысль в самом начале, а потому одна вода. Однако нет, через несколько десятков страниц стало гораздо интереснее и книга не отпускала меня вплоть до заключительного слова. О чем эта книга? — О том как построить карьеру в IT. Затрагивает многие аспекты — планирование, взаимодействие с бизнесом, выбор стека технологий…

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

Рекомендую к прочтению!

Django в одном файле!

Я тут размышлял на тему зачем нужен Flask (или другие микрофреймворки). И пришел к мысли, что единственный повод использовать Flask — если приложение настолько маленькое, что умещается в одном файле. А ведь в Django пустой проект — это уже нагромождение из нескольких файлов и папок. Для совсем крошечного приложения это пожалуй излишество.

И пока я думал. Мне в голову пришла мысль — дак ведь и Django, может работать из одного файла. В туториалах это конечно не описано, но для запуска тестов django-приложений у меня подобная схема уже используется.

Барабанная дробь! Запускаем Django-проект из одного файла! Та-да!

#!/usr/bin/env python
import os
import sys
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.http import HttpResponse
 
filename = os.path.splitext(os.path.basename(__file__))[0]
 
urlpatterns = patterns('',
    url(r'^$', '%s.home' % filename, name='home'),
)
 
def home(request):
    return HttpResponse('Django rules!')
 
if __name__ == "__main__":
    settings.configure(
        DEBUG=True,
        MIDDLEWARE_CLASSES = [],
        ROOT_URLCONF=filename
    )
 
    from django.core.management import execute_from_command_line
    execute_from_command_line([sys.argv[0], 'runserver'])

Все отлично работает. Теперь поводов использовать Flask не осталось и вовсе.
Кода конечно немного больше чем на Flask, но у проетов всегда есть потенциал вырасти, в этом случае мы легко сможем использовать огромное количество готовых приложений!
Примечание: запускал на Django 1.7.

От Python к Scala и C++

Благодаря PyPy мой код стал выполняться в 1.7 раз быстрее, но этого мне было не достаточно. Дальше я решил попробовать переписать парсер на Scala. Скала имеет статическую типизацию и компилируется в Явовский байт-код. Посмотрев тесты производительности я узнал, что Scala в 10 раз быстрее Питона и совсем чуть-чуть медленее чем C++. Конечно в это не очень верилось, но и с плюсами копаться не хотелось.

И вот я переписал код на Scala.

Python 7 мин 40 сек
PyPy 3 ммн 58 сек
Scala 4 мин 20 сек

Результаты скажем прямо меня не порадовали. Скала конечно быстрее CPython, но ведь это даже медленнее чем PyPy. Как вообще такое может быть, язык с динамической типизацией делает, язык со статической типизацией.

Вобщем я был в печали, но делать оставалось не чего, надо было выжимать максимум и я взял в руки С++.
Результат.
C++ 47 сек.

Вот это да! Вот это я понимаю, это реально быстро. 1,5Гб — файл разбирается за 47 секунд.

Однако копание в плюсах навело меня на следующую мысль. В плюсах я не использовал никакие высокоуровневые штуки для парсинга XML, лишь обычные строковые операции. А в Скале какую-то штуку для парсинга XML, а в Питоне регулярки. Получается тест не совсем честный, т.к. алгоритмы разные.

Я вернулся в Скалу и переписал код оставив только стандартные операции со строками.
И результат просто охренителен:
Scala 57 сек

Действительно почти также быстро как в плюсах.

Может реально вся проблема в алгоритме?

После этого я уже не мог не вернуться к Питону, чтобы выкинуть отуда все регулярки и узнать насколько же быстро может он парсить файлы.
Результаты:
CPython 4 мин 12 сек
PyPy 2 мин 48 сек

Да это в два раза лучше начальных результатов, но успех не такой громкий как в Скале.

Окончательные результаты:

CPython 4 мин 12 сек
PyPy 2 мин 48 сек
Scala 57 сек
C++ 47 сек.

Победитель — С++. А кто бы сомневался. Однако Scala настолько близка к плюсам по скорости, что это просто увидительно. Я еще окончательно не решил на каком языке теперь уже полностью перепишу парсер, пока склонаюсь к Scala.

Ускоряем Python — опыт применения PyPy

На одном из проектов уперся в производительность Питона. Такое бывает не часто, но бывает. Сначала думал о том, чтобы переписать код на более шустром языке — C/C++/Scala. Думал-думал, тем временем вспомнил о проекте PyPy(если кто не знает — это реализация Питона на Питоне). На сайте проекта есть тесты производительности, которые показывают что некоторые программы под PyPy начинают работать чуть ли не в 20 раз быстрее. Хотя в среднем ускорение куда меньше. Пишут что в среднем проекты ускоряются в 2 раза. Настроить PyPy куда проще чем переписать код на другом языке.

Очень подробная инструкция настройки PyPy находится здесь: http://doc.pypy.org/en/latest/getting-started.html

Все нужные пакеты установились без проблем — flask, pymongo, pytils, markupsafe, flexmock, nose.
Единственно что не смог установить это lxml, но он здесь мне и не был нужен.

Коненчно я был уверен, что теперь программа будет работать быстрее, оставалось узнать — на сколько быстрее. Результаты такие:
CPython — 5 часов.
PyPy — 3 часа.

Такоми образом ускорение получилось в 1,7 раз. Вот такие результаты. Хорошо это или плохо — зависит от проекта. В моем случае этого не достаточно, и я продолжил искать другие решения.

Ускрорение вставки в MongoDB

Сегодня немного потестил скорость вставки в Монге.
Количество документов 2 миллиона. Примерно такого вида:

{
	"store_id" : "mystore",
	"product_id" : NumberLong("8024090131402947")
	"available" : true,
}

1) Запись с уведомлением.
safe=True или w=1, j=0.
17 мин 4 сек

2) Запись без уведомления.
safe=False или w=0, j=0
4 мин 4 сек

3) Групповая вставка.
Операция insert в монге позволяет вставлять не только отдельный документ, но и массив документов. В этом случае документы вставляем не сразу, а накапливаем их по 1000 штук в буффер, затем разом вставлем.
1 мин 10 сек

Итого удалось ускорить вставку в 14 раз.

Bookradar — поиск книг в интернет магазинах

Bookradar — сайт, который осуществляет поиск книг в интернет магазинах за вас!

Порой не так просто найти некоторые книги, которые хочешь прочесть. Я чаще всего покупаю книги на Озоне, но в нем есть далеко не все книги. Более того, цены на некоторые книги прямо кусаются. Приходится искать в других магазинах где книга есть в наличии, сравнивать цены. Процесс в общем то простой. А если он простой, почему бы его не автоматизировать?

Именно такая идея пришла мне в голову однажды, да так крепко засела там, что не давала уснуть. Я понял, что пока не запишу все на бумагу, сна мне не видать. И я встал и пошел все записывать. Три часа спустя, я записал все мысли на 5 листах А4, а что-то даже зарисовал.

Спустя месяц появился bookradar.org. Ну как появился, не сам конечно же. Я усердно трудился над этим проектом все это время.

Как работает Bookradar?

Процесс поиска простой, вводишь все что помнишь о книге в поисковую строку, например название или автора. Не обязательно вводить название полностью, начни вводить, а Bookradar подскажет.

Нашел свою книгу? Теперь смотри где она есть и где дешевле — жми кнопку «Где купить?». Раскроется список с магазинами и ценами.

На некоторые книги цена в магазинах может различаться очень и очень сильно. Выбирай наиболее выгодное предложение или свой любимый магазин!

Добро пожаловать!

Этой статьей я хочу поделиться с вами радостью, от запуска своего нового сайта! Тем более что делать всякие промо сайты у меня уже поперек горла стоит, а тут реально клевый полезный сервис. Да и написал я его с применением новых для себя технологий. В частности одна из таких технологий это MongoDB. Я просто в восторге от нее! И почему я не использовал монгу раньше?

Добро пожаловать на bookradar.org!

Использование Sphinx с MongoDB

Рассмотрим подключение поисковика Sphinx к каталогу книг на MongoDB.

Sphinx умеет индексировать данные из MySQL и PostgreSQL. Также он имеет механизм для настройки индексации из произвольных источников, делается это с помощью xmlpipe2. Суть xmlpipe2 проста, нужно написать спкрит на любом языке который пишет в stdout xml-файл с данными для индексации.

На выходе дложен генерироваться подобный XML.

<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset>

<sphinx:schema>
<sphinx:field name="name"/>
<sphinx:field name="author"/>
<sphinx:field name="isbn"/>
</sphinx:schema>

<sphinx:document id="1234">
<name>Deadline. Роман об управлении проектами</name>
<author>Том Демарко</author>
<isbn>978-5-91657-150-9</isbn>
</sphinx:document>

<sphinx:document id="1235">
<name>Мифический человеко-месяц, или Как создаются программные системы</name>
<author>Фредерик Брукс</author>
<isbn>5-93286-005-7</isbn>
</sphinx:document>

В зависимости от данных можно указать разные поля. В моем случае это текстовые поля name, author, и ISBN. Сначала я написал тэг ISBN в верхнем регистре, но почему-то Сфинксу это не понравилось, пришлось указать в нижнем. И еще замечу id не может быть нулем или отрицательным числом.

sphinx.conf

source books {
    type = xmlpipe
    xmlpipe_command = python /path/to/xmlpipe.py
}

index books_index {
        morphology              = stem_enru
        charset_type            = utf-8
        source                  = books
        path                    = /path/to/data/sphinx/books
}

searchd {
    port                = 3312
    log                 = /path/to/searchd.log
    query_log           = /path/to/query.log
    pid_file            = /path/to/searchd.pid
}

Особеность MongoDB в том что идентификаторы документов не являются числами. Есть пара вариантов как это решить.

Вариант 1 — Используем счетчики

В MomgoDB нету поля auto increment, поэтому решаем это с помощью коллекции счетчиков (самая обычная коллекция)

db.counters.insert({_id: "books", value: 0});

при каждой вставке нового объекта проверяем текущее значение счетчика и прибавляем единицу, это и будет значение идентификатора нового документа.

Вариант 2 — Используем в качестве идентификатора числовой хеш

Если у наших объектов, есть глобальный идентификатор, например как ISBN у книг. Мы можем использовать в качестве идентификатора 64-битный хеш. С учетом того что 64 битное число в MongoDB имеет знак (спецификация BSON), мы можем использовать только 63-бита. Вобщем тоже неплохо.

Питон легко работает с числами произвольной точности. А вот Sphinx по умолчанию понимает беззнаковые 32-битные числа, чтобы он понимал беззнаковые 64-битные числа нужно собрать его указав специальную опцию.

$ ./configure --enable-id64
$ make 
$ sudo make install

На этом технические нюансы не заканчиваются. Дело в том что в Javascript для представления 64-битных чисел используется формат double. Максимальная точность лишь 53 бита. Это может представлять проблему, если вы захотите поиграться с этими числами в терминале монги. Можете сравнить выполнив в терминале монги Math.pow(2,60) и с аналогичной операцией в питоне. Если же вы не собираетесь произваодить математических операций в терминале монги, то с 63 битными хешами не должно быть проблем.

В итоге я предпочел писпользовать 53-биный хеш для получения идентификатора.

> Math.pow(2,53)
9007199254740992

В этом случае максимальное число довольно большое и если у меня миллион объектов то вероятность коллизий очень низка, что мне походит. Кому ненулевая вероятность коллизий не подходит лучше использовать вариант со счетчиками.

Пример 53-битной хеш-функции.

import hashlib

def hash53(text):
    return long(hashlib.md5(text).hexdigest(),16) & long('1'*53,2)

Тут мы испоьзуем любой из стандартных хешей (md5, sha1, и пр.) с равномерным распределением и берем младшие 53 бита.

Ссылки
https://en.wikipedia.org/wiki/Double_precision
http://sphinxsearch.com/docs/current.html#xmlpipe2
http://bsonspec.org/#/specification