Подписка на блог

В Телеграме помимо ссылок на заметки делюсь околодизайнерскими наблюдениями.

В Твиттере помимо ссылок на заметки пишу всякую чушь.

В Тумблере и Же-же есть автоматические трансляции. Если не работает, напишите мне: ilyabirman@ilyabirman.ru.

По РСС и Джейсон-фиду трансляции для автоматических читалок

Эгея

Эгея — движок блога, на котором работает этот сайт.

Описания версий

2.3 · 2.4 · 2.5 · 2.6

Некоторые заметки

Почему заметки в РСС Эгеи могут повторяться

Потому что у вашего блога несколько адресов-синонимов и не настроен редирект на канонический адрес. Сейчас объясню.

Об определении новых заметок

Иногда люди жалуются, что от некоторых блогов на Эгее заметки «приходят по два раза» (или даже больше). Такое, например, было у Максима Ильяхова.

Чтобы разобраться, в чём дело, важно сначала понять, что заметки по РСС никуда не «приходят». РСС — это просто формат, в котором отдаётся лента. Читалка смотрит, не появилось ли в ленте новое, и, если появилось, показывает вам это как непрочитанное. Разумеется, каждая заметка в ленте встречается один раз — можете сами в этом убедиться на любом проблемном блоге. Но что-то заставляет читалку при очередном взгляде на ленту считать, что заметки из неё она ещё не видела, и нужно показать вам их как новые.

Чтобы понять, видела читалка заметку или нет, она смотрит не в текст заметки, а в РСС-тег <guid>. Этот тег должен содержать некий глобально уникальный идентификатор заметки. Традиционно для этого используют просто адрес заметки, и в этом случае ещё ставится атрибут isPermaLink.

Например, у этой заметки в ленте написано так:

<guid isPermaLink="true">
  http://ilyabirman.ru/meanwhile/all/aegea-rss-duplication/
</guid>

Об адресах-синонимах

Мой блог доступен по нескольким другим адресам, например:

И по всем возможным сочетаниям этих доменов и путей, с www и без. Однако у меня настроены редиректы. Если вы зайдёте не по каноническому адресу, вы автоматически перейдёте на канонический — попробуйте сами.

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

Это ошибка в настройке сервера: кроме владельца сайта никто не знает, что эти адреса — синонимы, и для внешнего мира всё выглядит так, будто есть несколько сайтов с одинаковым содержимым. Наверное, поисковики умеют такое отслеживать и понимать, но РСС-читалке неоткуда знать, что ilyabirman.ru и ilbi.ru — это один сайт (не пойдёт же она их постранично сравнивать).

Так почему возникают дубликаты-то?

Предположим, у меня бы не было редиректов, и кто-то бы подписался на РСС с сайта ilbi.ru/blog. Тогда в его РСС-ленте «уникальный» идентификатор этой заметки выглядел бы уже вот так:

<guid isPermaLink="true">
  http://ilbi.ru/blog/all/aegea-rss-duplication/
</guid>

Само по себе это не было бы проблемой, ведь для каждого конкретного подписчика эти адреса действительно уникальны. Если кто-то подписался на ilbi.ru/blog, то в его РСС-потоке неоткуда же взяться заметке с адресом ilyabirman.ru? Есть: из кеша!

Когда читалка первый раз просит у Эгеи РСС конкретного блога, Эгея генерирует его, отдаёт читалке и сохраняет себе локально, в кеш. Поэтому когда читалка (эта же или другая) спрашивает ещё раз, Эгея просто отдаёт готовый файл, ничего не генерируя. Когда автор добавляет или редактирует заметку, Эгея удаляет устаревший кеш, и следующий соберёт только тогда, когда какая-то читалка её попросит.

Получается, что когда читалка обращается за РССом, Эгея отдаёт его из кеша, где все идентификаторы зависят от того, по какому адресу у неё спрашивали РСС первый раз после последнего изменения. Когда читалка, которая в прошлый раз видела десять заметок с идентификатором ilyabirman.ru/что-то, видит десять новых заметок с идентификаторами ilbi.ru/что-то, она думает, что перед ней новьё — вот и показывает всё это как непрочитанное.

Так падажжи

Тут у вас могут возникнуть вопросы.

— Что мешает Эгее во избежание этой проблемы писать идентификаторы всегда с одним адресом, даже если она доступна по нескольким?

Не только внешний мир без редиректа не знает, что ilyabirman.ru и ilbi.ru — это одно и тоже. Эгея, чтобы узнать, на каком сервере она работает, смотрит, по какому адресу её открыли — больше ей это узнать неоткуда. Если её открыли по адресу ilbi.ru, то в её вселенной просто не существует набора символов «ilyabirman.ru», чтобы засунуть его в РСС. То, что он оказывается в кеше — чистая случайность.

Конечно, можно вести отдельный список всех адресов, по которым данная копия движка когда-либо открывалась, и всегда ставить в РСС первый из них. Но это ужасный костыль, и если автор от одного из синонимов откажется в будущем, а он как раз окажется первым в этом списке, у него просто сломается РСС, и он никогда не поймёт, почему.

— Что мешает в качестве уникальных идентификаторов отдавать какую-то случайную (но постоянную для заметки) шестнадцатиричную фигню, чтобы вообще не завязываться на адреса?

Помимо того, что это тоже костыль и усложнение движка, проблема ещё вот в чём. Отдавать именно адрес заметки в качестве идентификатора принято в мире РСС — я за всю жизнь не видел ленты с другими идентификаторами. Я боюсь, что какие-то читалки могут на это полагаться, и что-нибудь в них сломается, если сделать иначе.

Помимо этих я могу придумать ещё много вариантов того, как обойти эту проблему, но все они имеют серьёзные недостатки. Ну, например: можно хранить раздельные кеши для всех адресов, по которым заходят в блог — и занимать в несколько раз больше места на диске, чем нужно. Или: не кешировать РСС вообще — и увеличивать нагрузку на сервер не по делу. Но главное, мне не нравится сама идея пытаться из последних сил работать в шизофреническом окружении.

Вывод

РСС ломается, потому что вы делаете странное: у вас сайт одновременно и один, и несколько. Настройте редиректы, сбросьте кеш и всё будет хорошо.

14 августа   Эгея

Помочь запустить хостед-версию Эгеи

Мне нужен человек, с которым мы вместе запустим хостед-версию Эгеи.

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

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

При этом нужно, чтобы сам этот сервер был дешёвым.

Ещё важнее, чтобы затраты были предсказуемыми. Представьте, что блог на такой Эгее заведёт фотограф, будет выкладывать фотографии десятками, а потом на его удачный пост даст ссылку Лебедев. Что делать, чтобы я при этом не разорился?

Если вы предложите хранить саму Эгею в одном месте, а все медиафайлы пользователей — в другом, то надо будет научить Эгею загружать файлы на другой сервер, чем её собственный. Пока не знаю, насколько это сложно.

Если пользователь заведёт хостед-Эгею, он должен иметь возможность привязать её к своему домену или поддомену, а в идеале — даже к конкретному собственному урлу. Я даже примерно не представляю, как это настраивается, но мне надо, чтобы вы это знали.

Если вы готовы предложить свою помощь, напишите мне, пожалуйста, письмо (почта — в подвале каждой страницы). Сразу же расскажите о том, что хотите взамен.

26 июля   вопрос   Эгея

Компании, ставьте Эгею

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

Эгея — это движок блога. То есть программа, которая работает на сайте компании и предоставляет ей инструменты для ведения блога, а посетителям показывает заметки и даёт писать комментарии (если это нужно).

Сделайте блог на Эгее частью сайта своей компании.

Эгея умеет мимикрировать под стиль сайта. С её помощью можно организовать раздел «Блог», который будет выглядеть как страница вашего сайта. Так сделано у меня. Со стороны и не скажешь, что блог — отдельный кусок сайта, выглядит-то так же.

После того, как Эгею установишь, пользователю не нужно ничего знать про серверы, базы данных и ХТМЛ. Нет даже никакой «админки» — всё управление происходит прямо на сайте. Просто тот, кому можно, видит иконки «плюсик» (добавить заметку), «карандашик» (отредактировать заметку) и ещё несколько.

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

Компании, ставьте Эгею

Справа сверху — иконки новой заметки, черновиков и настройки, чуть ниже — мусорка, чтобы удалить.

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

К разделу блога легко прикрутить аналитику — просто вставляете код в настройке:

Эгея 2.6 и платные фичи

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

Напишите мне, если хотите начать пользоваться, но не знаете, как начать.

Расскажите компаниям об Эгее, а мне — о компаниях, которым она, на ваш взгляд, будет полезна.

19 июля   Эгея

Эгея v3118

Вышла новая сборка Эгеи, v3118.

Недавно я задавал вопрос про фоновую работу ПХП на ХТТПС. По вашим советам перешёл на curl и всё стало прекрасно работать. Если у вас ХТТПС, вам стоит обновиться, иначе у вас может плохо работать поиск и не работать бекап и подтягивание обложек видосов.

Ещё в этом билде сильно оптимизирована обработка строк. Если вы страдали от медленного сохранения больших заметок, вам стоит обновиться.

Обновляться как обычно — заменить папки /system/, /themes/plain/ и файл .htaccess в корне.

5 июня   Эгея

Вопрос про фоновую работу ПХП

Эгея написана на ПХП как обычное веб-приложение, отвечающее на запросы браузера к серверу. Браузер просит страницу — Эгея её генерирует и отдаёт.

Часть работы, которую делает Эгея — медленная по своей природе, например создание бекапа или индексация большого блога для поиска. Но Эгея отдаёт страницы быстро.

Это потому что в Эгее реализован механизм фоновой работы через запрос к себе. Когда нужно сделать что-то долгое, Эгея устанавливает ХТТП-соединение сама с собой, как бы делая вид, что она браузер, отправляет запрос по специальному урлу, который означает «сделай бекап» или «поиндексируй поиск», и тут же обрывает соединение. В результате выполнение скрипта заканчивается быстро, а вся долгая работа делается незаметно, как раз в ответ на этот запрос к себе. О таком методе я узнал лет двенадцать назад от Романа Иванова, и с тех пор пользуюсь.

Асинхронное выполнение на ПХП

К сожалению, с этим методом возникла проблема, когда я стал поддерживать ХТТПС. Если просто отправлять запрос и сразу закрывать соединение, как я всегда делал, не происходит вообще ничего — с точки зрения сервера всё выглядит так, как будто к нему и не обращались. Если же попробовать прочитать ответ, то приходит 400 Bad Request, потому что я как бы пытаюсь говорить с ХТТПС-сервером на простом ХТТП. К сожалению, мне почему-то так и не удалось отправить самому себе запрос по ХТТПС с помощью функции fsockopen () и её родственников, хотя я вроде бы исчитал документацию со всех сторон.

Вместо запроса к себе можно использовать register_shutdown_function (). Но я когда-то пользовался ей, и у меня осталось ощущение ненадёжности — кажется, она выполнялась не всегда, и там были какие-то особенности внутри странные, например, что все пути к файлам должны быть указаны абсолютно. Короче, чтобы ей воспользоваться, нужно переструктурировать код. Женя Степанищев ещё рассказал про fastcgi_finish_request () — похожий вариант.

Эти схемы мне не нравятся непрозрачностью: часть скрипта будет выполняться в каком-то мире, который не виден никому. В варианте с запросом к себе мне ничто не мешает зайти браузером по моему служебному урлу и посмотреть, что происходит. А тут придётся что-то специальное изобретать для отладки. Кроме того, запрос к себе, разумеется, запускает новую копию ПХП, в которой заново начинается отсчёт времени. Выполняя такой запрос, я могу теоретически захотеть сделать что-то ещё так же, и инициировать запрос третьго уровня. И все эти запросы — одинаковой природы, просто заход по урлу. Мне нравится эта однородность.

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

Ну и пока умники в твиттере не начали писать «расскажите кто-нибудь Бирману про крон», объясню, что моя задача — сделать максимально автономное решение, не требующее от пользователя никакой специальной настройки сервера. Закачал на сервер папку — всё работает. Если вы матёрый программист в свитере, вам такое не понять.

Короче, в идеале я бы хотел заставить работать свою исходную конфигурацию. Для этого мне нужно научиться делать запрос к себе по ХТТПС. Причём мне нужно просто «потрогать» нужный урл и отвалиться — мне не нужно по нему передавать никаких данных, не нужно читать ответ. Как это сделать?

Ну и если вы знаете какой-то ещё способ добиться нужного результата, лишённый всех описанных недостатков, тоже расскажите.

24 мая   веб-разработка   вопрос   ПХП   Эгея

Эгея v3109

Вышла новая сборка Эгеи, v3109.

В ней исправлен баг, который был случайно введён в сборке v3107 на днях. Из-за него редактор мог повесить браузер. С v3107 надо обновиться обязательно, с v3101 — если вас беспокоит баг с незагружаемостью картинок.

После выхода новой версии всегда есть небольшая турбулентность, пардон.

2017   Эгея

Эгея v3107

Вышла новая сборка Эгеи, v3107.

Из заметного с момента релиза 2.6 — исправлен баг, из-за которого картинки могли не загружаться у тех, у кого в урлах используется ?go=. Пока все те, кто поймал этот баг, в итоге перешли на чистые урлы, чем и исправили баг, и получили чистые урлы. Так что от бага они только выиграли.

О том, как сделать чистые урлы, написано в документации («Движок использует в урлах конструкцию ?go=, а я хочу чистые урлы без неё»). Эгея автоматически использует чистые урлы, когда уверена, что они у вас заработают, но она не всегда может быть уверена, поэтому иногда нужны такие пляски с бубном.

Но баг всё же стоило исправить, потому что на чистые урлы могут перейти не все.

2017   Эгея

Эгея 2.6

Готова Эгея 2.6 (сборка v3101) с автосохранением, новым поиском и платными фичами. Эта заметка частично повторяет анонс беты и заметку о платных фичах, чтобы всё было в одном месте.

Локальное автосохранение заметок

Заметки теперь непрерывно сохраняются в браузере, пока их пишешь, поэтому изменения не потеряются, если пропадёт интернет или отрубится электричество. В анонсе беты я в деталях писал, как это работает.

Эгея 2.6 бета

Красная точка слева — признак того, что есть несохранённые изменения. Если закрыть редактор, а потом открыть заново, он откроется ровно в таком же состоянии: с тем же текстом, с той же красной точкой, означающей, что данные не сохранены, и с курсором, мигающим в том же месте. Чтобы вернуться к сохранённой версии, нажмите ⌘ Z.

Красная точка помогает найти заметки, в которых есть несохранённые изменения:

Эгея 2.6 бета

Локальное автосохранение работает только для заметок и черновиков. Его нет у тегов и комментариев.

Автосохранение запрограммировал Игорь Адаменко — он же ранее помогал мне с новой версией моего сайта. Игорь крутой.

Новый поиск

Поиск научился склонять слова, а выдача стала намного удобнее: вместо простыни заметок она показывает небольшие «сниппеты», содержащие найденный фрагмент текста и все картинки из заметки. Узнать нужную заметку по картинкам — самый кайф:

Эгея 2.6 бета

Избранные заметки имеют больше веса при поиске.

Поиск работает на «Розе» — встраиваемом поисковом движке Романа Парпалака, об использовании которого я недавно писал.

Если у вас много заметок, Эгее понадобится несколько минут после обновления, чтобы сначала всё проиндексировать. Результаты поиска в это время будут показываться по старой технологии. Вам ничего не нужно делать, Эгея управляет индексацией сама.

Картинки и обложки в редакторе

Эгея с прошлой версии отдаёт картинки в качестве «обложек» при отправке ссылок в соцсети. Но теперь она умеет отдавать так и стоп-кадры видеороликов с Ютюба и Вимео. Ну и заодно у заметок с видеороликами появился шаринг в Пинтерес.

Кстати, эти стоп-кадры попадают и в выдачу поиска наравне с другими картинками, что тоже упрощает нахождение глазами нужной заметки.

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

Раньше Эгея считала, что картинка используется в заметке, только если её упоминание было в тексте заметки. А если удалить упоминание из текста, то картинка «терялась» и из превьюшек снизу. Теперь это независимые вещи: заметка помнит загруженные в неё картинки, даже если они не используются в тексте.

Это даёт несколько приятностей:

  1. Обложкой для соцсети может быть картинка, которая не используется в самой заметке. Просто загрузите картинку в заметку, но не вставляйте её название в текст. Для этого перетащите её на страницу заметки, но за пределы текстового поля (раньше можно было перетащить только в текстовое поле).
  2. Если вы перетаскивали картинку, но файл с таким именем уже был на сервере, Эгея переименовывала его, добавляя в конец число. В прошлой версии добавилось перетаскивание с зажатым Альтом — в этом случае старая картинка заменялась новой. Теперь работает чуть умнее: если на сервере файл есть, но это тот же самый файл, то она просто добавляет его в ту заметку, куда вы его перетаскиваете, не делая бессмысленную копию на сервере.
  3. Когда вы удаляете картинку из превьюшек в редакторе, раньше Эгея просто удаляла файл на сервере. Теперь так делать нельзя, ведь «официально» поддерживается использование одного файла в нескольких заметках. Эгея смотрит, не используется ли файл где-то ещё, и удаляет его только, если он больше нигде не нужен.
  4. Наконец, Эгея не «потеряет» картинку просто из-за того, что вы убрали её имя текста заметки.

Ещё теперь можно загружать картинки в СВГ.

Всё, что я написал про картинки, верно и для аудиофайлов. Но аудиофайл или СВГ не могут быть обложками для соцсетей.

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

Теперь стандартное форматирование Эгеи поддерживается внутри тегов div, table и blockquote. Если вы хотите поставить текст на плашку или разбить на колонки, можете это сделать, а внутри продолжать использовать привычный синтаксис.

Фичи для платных пользователей

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

В настройке появились поля Яндекс-метрики и Гугль-аналитики:

Эгея 2.6 и платные фичи

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

При просмотре черновиков снизу появилась «Секретная ссылка»:

Эгея 2.6 и платные фичи

Это ссылка на черновик, которую можно дать кому-то, чтобы он увидел черновик. Я этим пользуюсь, когда публикую рекламу: присылаю рекламодателю, чтобы он утвердил заметку перед публикацией. Если черновик отредактировать, ссылка «сгорает», нужно взять новую.

С бесплатной версией можно — и всегда можно было — просто прислать скриншот.

Теперь вы можете легко прикрутить свою кнопку «Подписаться» (см. у меня под заметкой). Это реализовано через допблок subscribe-sheet. Вы пишете ХТМЛ того, что будет внутри окна подписки, а кнопка под заметками появляется сама. При этом там есть готовые куски, чтобы сделать логотипы фейсбуков и прочего.

Так выглядит комплектное, не настроенное окно подписки:

Эгея 2.6 и платные фичи

Заходите в шаблон, убираете лишнее, вставляете свои ссылки — и готово. Если нужны другие соцсети, иконку придётся нарисовать свою. Бардак с русским и английским тут связан с тем, что выбран русский язык интерфейса, но локализованы только заголовок окна и слово «РСС» . Я решил, что локализовывать названия соцсетей смысла нет, потому что вы всё равно сможете написать тут что хотите.

В бесплатной версии можно — и всегда можно было — сверстать это вручную.

И ещё одна фича — глобальные стили. Это немного облегчает прикручивание Эгеи в качестве одного из разделов большого сайта, где уже есть свои стили. Например, на моём сайте с ранних бет 2.6 Эгея использует ЦСС от основного сайта. Для этого надо в файле theme-info.php от вашей темы оформления прописать ключ global_styles. У меня этот файл выглядит так:

<?php return array (
  'display_name' => 'Минвайл',
  'max_image_width' => '1200',
  'global_styles' => '../css/main.css',
); ?>

В бесплатной версии можно — и всегда можно было — в своей теме оформления копировать стили от основного сайта. Я это раньше делал «Галпом», чтобы два раза не писать, а теперь вот не надо.

Если у вас уже есть платная лицензия, и вы хотите сборку беты 2.6 с этими фичами, напишите мне письмо.

Теперь снова о том, что доступно всем.

Автомиграция при подключении к старой базе

Когда вы обновляли Эгею, она меняла структуру базы данных для совместимости с новой версией — так было всегда.

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

Теперь движок наоборот исходит из того, что данные в базе могут быть в любом формате, начиная с формата Эгеи 2.0. Если вы устанавливаете движок начисто, а не обновляетесь, но при этом говорите, что данные в базе уже есть, или просто подключаетесь к другой базе в настройке, движок сконвертирует базу в актуальный формат.

Остальное

Исправлена куча багов. Но этим никого не удивишь.

При редактировании описания тега теперь тоже можно загружать файлы. Короче, описание тега теперь может выглядеть как полноценная заметка, у него тоже работают всякие обложки. Редактор тега открывается по Alt+E на странице тега, как у заметки. А сохранение изменений в описании тега заработало в сто раз быстрее.

Для залогиненного автора быстрее открываются заметки с кучей комментариев.

Изменилась логика включения комментариев. Раньше был глобальный флаг «разрешить комментарии», но можно было выключить индивидуально у отдельных заметок. Теперь глобального флага нет, комментарии настраиваются у заметок по отдельности. А глобально настраивается, врубать ли комментарии заметкам во время публикации по умолчанию или нет.

Основной кегль текста в комплектной теме увеличен с 15 до 16 пунктов. Знаки валют прикрепляются к суммам неразрывным пробелом. Форма логина заадаптивилась (в 2.5 недоглядели).

На странице удаления заметки появилась кнопка «Вернуть в черновики». На страницах архива, где показывают заметки списком ссылок, избранные заметки помечаются звёздочками. Добавилась поддержка шаринга в Линкед-ин (потому что обновился Лайкли).

Технические детали

Движок лучше распознаёт, что работает по ХТТПС, и отдаёт по этому же протоколу всякие скрипты и картинки.

Добавилась поддержка Апача 2.4, у которого с какого-то бодуна изменился на полностью нечитаемый синтаксис некоторых опций конфигурации. Движок должен работать под ПХП 7.0 и 7.1 — я теперь тестирую локально под семёркой. А на моём сайте, наоборот, крутится ПХП 5.3 — это теперь низшая из поддерживаемых версий.

Все скрипты теперь минифицируются.

Файл, в котором хранятся параметры настройки теперь называется не settings.psa, а settings.json. Если вдруг захочется вручную что-то отредактировать, теперь это удобнее.

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

Где скачать

Свежий дистрибутив — на сайте движка.

2017   продукты   релиз   Эгея

Как прикрутить поисковый движок «Роза»

Я уже рассказывал, что в новой Эгее 2.6 — новый поисковый движок «Роза» Романа Парпалака. На примере Эгеи расскажу немного о том, как вы можете использовать его в своих продуктах.

Что делает Роза

Роза — движок поиска по переданным ему данным.

У Розы нет «паука» для индексации. Это специально. В случае с движком блога, например, нет никакого смысла искать ссылки, ходить по страницам, разбирать их код. И ещё убеждаться, что не индексируешь одну и ту же заметку несколько раз, потому что она встретились на страницах разных тегов. Это лишняя работа: приложение-клиент знает, как устроены данные в нём, и может отдавать их поиску сразу «в чистом виде».

Роза понимает три команды: «проиндексируй вот это», «удали из индекса вот это» и «найди всё вот по этому запросу». Как устроен индекс и как она находит — клиенту знать не нужно, это чёрный ящик. Клиент должен только обеспечить Розе доступ к хранилищу, где она будет держать индекс, и своевременно сообщать об изменениях, чтобы этот индекс был актуален.

Таким образом, поиск — это взаимная работа клиента и Розы. Прикрутить её сложнее, чем использовать движок поиска общего назначения. Зато понимание структуры данных позволяет гибко форматировать результаты и учитывать их природу при ранжировании.

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

Как прикрутить поисковый движок «Роза»

Теперь к делу.

Хранилище

Хранилище — это объект, через который Роза взаимодействует с базой данных. Клиенту нужно передавать его Розе и для индексации, и для поиска. Поэтому удобно иметь функцию, которая его отдаёт, когда нужно:

function e2_rose_storage () {
  static $pdostorage = null;

  if ($pdostorage === null) {
    $pdo = new \PDO (
      'mysql:'.
      'host='. $_db_server .';'.
      'dbname='. $_db_name. ';'.
      'charset=utf8',
      $_db_user,
      $_db_password,
    );
    $pdo -> setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    $pdostorage = new PdoStorage ($pdo);
  }

  return $pdostorage;
}

Для простоты я убрал некоторые специфичные для Эгеи вещи. Я тут проверяю, нет ли уже и так созданного хранилища; если нет, то создаю; и в любом случае его возвращаю. На место переменных, начинающихся с подчёркивания, надо поставить настоящие реквизиты базы данных.

Индексация

Задача клиента — «рассказать» Розе о данных, чтобы она построила свой индекс. Для этого нужно добавить каждую сущность (в Эгее — заметку) в индекс:

$stemmer = new PorterStemmerRussian ();
$indexer = new Indexer (e2_rose_storage (), $stemmer);
$indexable = new Indexable (
  $_note_id,
  $_note_title,
  $_note_text
);
$indexer -> index ($indexable);

Когда пользователь публикует или изменяет заметку, я вызываю этот код. По идентификатору Роза понимает, нужно ли добавить в индекс новую запись или переиндексировать старую.

Стеммер — это объект, к которому обращается Роза, чтобы сравнивать слова в разных падежах и формах. Его нужно передавать при индексации и при поиске. Он обособлен для того, чтобы можно было сделать свой стеммер для другого языка и подключить, не меняя ничего в индексаторе и поисковике.

Как видите, на индексацию я передаю идентификатор, заголовок и текст заметки, а не адрес её страницы. Когда Роза что-то находит, она мне так же возвращает список идентификаторов найденных сущностей, а не ссылки. Построить страницу выдачи с рабочими ссылками — моя забота (но Роза поможет подсветить результаты поиска в выдаче — об этом ниже).

Можно отдавать и адрес страницы при индексациии, но для Розы это просто текстовое поле, она не пойдёт по этому адресу низачем, просто вернёт его потом вместе с результатами поиска. Я этим не пользуюсь, потому что мне сподручнее получить адрес заметки из неё идентификатора, а не от Розы.

Индексация одной заметки — быстрая операция, поэтому поддержание индекса в актуальном состоянии не составляет проблемы.

Но при обновлении Эгеи со старой версии, мне нужно аккуратно проиндексировать все написанные ранее заметки. В случае с моим блогом это около четырёх тысяч заметок. Поэтому просто запустить их индексацию в цикле нельзя: даже если операция уложится во временной лимит ПХП, всё это время пользователь будет думать, что сайт не отвечает. А если не уложится, то пользователь вообще ничего не увидит. Как обеспечить безболезненную фоновую индексацию — тема отдельной заметки, но важно, что это забота клиента, а не Розы.

Когда пользователь удаляет или отзывает заметку, я делаю примерно так:

$stemmer = new PorterStemmerRussian ();
$indexer = new Indexer (e2_rose_storage (), $stemmer);
return $indexer -> removeById ($_note_id);

Поиск

Чтобы искать, нам понадобится файндер (а ему понадобится стеммер):

$stemmer = new PorterStemmerRussian ();
$finder = new Finder (e2_rose_storage (), $stemmer);
$finder -> setHighlightTemplate (
  '<span class="'.CSS_CLASS_HIGHLIGHT.'">%s</span>'
);

Здесь я также настраиваю шаблон для подсветки найденных слов в результатах поиска.

Теперь можно сделать запрос и достать результаты поиска:

$rose_query = new Query ($query);
$rose_query -> setLimit (SEARCH_LIMIT); 
$resultSet = $finder -> find ($rose_query);

Тут я не могу продолжать как ни в чём не бывало и не сделать ремарку. Объекто-ориентированное программирование делает мне больно. Просто так написать нельзя:

$results = rose_find ($db_link, $query, SEARCH_LIMIT);

С объектами для выражения простых мыслей требуется много строк. Связанные фрагменты кода невозможно разместить в поле зрения, и постоянно приходится скролить туда-сюда, держа вещи в памяти. Я понимаю, что объекты имеют преимущества. Но когда-нибудь программисты поймут, что так писать — тоже не дело, и придумают способ вернуть коду выразительность, не потеряв той пользы, которую им приносят объекты.

Итак, после того, как мы получили $resultSet, мы уже можем выводить результаты. Но это тот момент, когда можно попросить Розу подкрутить релевантность, что я и делаю:

foreach ($resultSet -> getFoundExternalIds () as $external_id) {
  $note_id = e2_note_id_from_rose_id ($external_id);
  $note_rec = e2_note_by_id ($note_id);
  if ($note_rec['IsFavourite']) {
    $resultSet->setRelevanceRatio ($external_id, 2);
  }
}

Так я поднимаю избранные заметки повыше.

Тут же Розу можно попросить сделать «сниппеты» — так называются фрагменты, выводящиеся в результатах поиска. Роза сама находит предложения с найденными словами, подсвечивает в них эти слова и собирает маленький кусок текста, достаточный для узнавания заметки в выдаче. Это делается так:

$snippetBuilder = new SnippetBuilder ($stemmer);
$snippetBuilder -> setSnippetLineSeparator(' · ');
$snippetBuilder -> attachSnippets ($resultSet, function (array $external_ids) {
  $result = array ();
  foreach ($external_ids as $external_id) {
    $note_id = e2_note_id_from_rose_id ($external_id);
    $note_rec = e2_note_by_id ($note_id);
    $note_pack = e2_package_note ($note_rec);
    $result[$external_id] = $note_pack['text'];
  }
  return $result;
});

Чтобы собрать сниппеты, Розе нужны полные тексты заметок — сама она их не хранит, а о структуре моей базы данных ничего не знает. Поэтому в метод attachSnippets мы тут передаём колбек, который Роза вызывает, чтобы их получить. Он, как видите, вытаскивает заметки из базы.

После этого можно собрать результаты:

foreach ($resultSet -> getItems () as $external_id => $item) {
  $note_id = e2_note_id_from_rose_id ($external_id);
  $note_rec = e2_note_by_id ($note_id);
  $note_pack = e2_package_note ($note_rec);
  $note_pack['title' ] = $item -> getHighlightedTitle ($stemmer);
  $note_pack['text' ] = '<p>'. $item -> getSnippet () .'</p>';
  $note_packs_found[] = $note_packs;
}

Я подсвечиваю найденные слова в заголовке и показываю сниппет вместо текста заметки.

Код выдачи результатов поиска неэлегантен — хотя бы потому, что я трижды прохожусь циклом по этим результатам, многократно вызываю одни и те же функции с одними и теми же параметрами. Никаких измеримых проблем эта неэлегантность не создаёт, а её исправление потребовало бы изменения АПИ Розы. Поэтому пока пусть будет так.

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

Если захотите использовать Розу в своих продуктах, своими мыслями делитесь с Романом, а не со мной.

Эгея v3094

У меня новая сборка беты Эгеи 2.6.

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

Ну и ещё исправлено всякое по мелочи (в том числе в работе по ХТТПСу).

Ссылка: e2_distr_v3094.zip Релиз.

2017   продукты   релиз   Эгея
Ранее Ctrl + ↓