Title, индексация и поиск (историческая статья)
С самого начала создания Rext с помощью FieldProcessing (создание полей) мы выделили некоторые базовые параметры страницы в отдельные поля. По-умолчанию, в PmWiki поле Дата недоступно пользователю и содержит автоматически заполняемую дату последнего изменения страницы. Поля description и title предлагается заполнять в теле страницы командами (:description:)
и (:title:)
соответственно. Мы их смело вынесли, а вот последствия этого шага стали ясны только сейчас.
С точки зрения архитектуры системы, исходная логика объяснима, Первоначально PmWiki — это система для создания Баз Знаний, энциклопедий. Предполагалось, что в ней будут храниться в основном термины / понятия на английском языке. Для этого в большинстве случаев подходят обычные URL, как мы знаем по Википедии. Поэтому неудобный (:title:)
не предполагалось часто использовать. При этом вся ключевая информация хранилась в одном поле, что, как мы увидим ниже, удобно для индексации.
Однако при адаптации под российско-кириллическую действительность этот подход пришлось изменить, и вот почему:
- вот как выглядят полностью кириллические ссылки при их копировании через буфер обмена: 96b8b7bd8c/a1bfbe8082 :(
- сложившая практика SEO в нашей стране отдает предпочтение транcлитерированным URL, похожим на кириллический
<h1>
; - при использовании PmWiki в качестве Блога, заголовки не будут короткими, и их уж точно невозможно будет автоматически "восстановить" их из URL, как в оригинале.
Конечно, можно было бы создавать все новые страницы с автоматически подставляемым кодом вида (:title Title, индексация и поиск (историческая статья):)
, однако это сильно усложнило бы масштабирование в дальнейшем, например внедрение EditTemplates.
Одним словом, по историческим причинам поля вынесены.
Так к чему же это привело?
К тому, что PmWiki перестала искать по ним. По-умолчанию, pagelist делает поиск пользуясь $PageIndexFile. В этот файл, кроме служебных данных, для каждой страницы записывается две вещи:
- содержимое поля targets (т.е. backlinks, как хорошо, что при реализации MultyTags внутренний голос подсказал не создавать новое поле, а сделать лишь легкую надстройку над существующим)
- индекс всех слов страницы
Таким образом, выполнение (:pagelist:)
существенно ускоряется, особенно при поиске одиночных слов.
Однако в индекс попадает только содержание страницы. До выделения отдельных полей это не было проблемой, а теперь туда не попадает информация, содержащаяся в заголовке.
Что с этим можно сделать?
Вариант №1: попробовать включить кастомные поля в механизм индексации
Этот код живет в файле pagelist.php, функция PageIndexUpdate. Легко видеть, что ничего не получится. В функции не заложено подобной масштабируемости, надо конкретно править ядро, причем придется просить ведущего разработчика внедрить функционал, и это будет очень непросто. Кроме того, наверняка это не единственное место. Теоретически, PmWiki ведь должна работать и без индекса.
В общем, вариант отпадает.
Вариант №2: отнестись с этому философски
Плохо, что текст заголовков не попадает в поиск, зато поиск по заголовкам/дескрипшенам может быть отделен от прочих результатов, и, например приоритезирован.
Далее открывается некоторое поле для фантазии. Можно внедрить HttpVariables и после этого действовать примерно такими путями:
- на Search сделать два последовательных вывода результатов — сначала совпадения в заголовках, потом в телах. Поиск получит некоторую релевантность. В принципе, можно наверное даже всю логику всунуть в один
(:searchbox:)
- при заполнении формы, можно быстренько делать AJAX-запрос и подгружать ссылки на статьи с совпадающими заголовками. Или даже не AJAX, если сайт не огромный, можно сгенерить всю его "карту" на странице поиска в скрытом виде.
В любом случае, остаются следующие минусы:
- богатый синтаксис Search будет неприменим для поиска по заголовкам
- некоторая просадка по производительности.
Итак, что же далеко ходить, вот базовый пример формы, осуществляющий выборку по полю title (используем HttpVariables для получения GET-параметров):
(:input form method=get:) (:input search query value="{$?query}" :) (:input submit value="Искать":) (:input end:) (:if !equal {$?query} "":) Результат поиска ''{$?query}'': (:pagelist $Title=*{$?query}* fmt=#title :) (:ifend:)
update:
Чтобы выборка корректно обрабатывала и "на литом", и "На литом", т.е. обучить ее пробелам и игнорировать большую букву, приходится костылить:
PhQuery:"*{(tolower "{$?query}")}*,*{(ucfirst "{$?query}")}*" (:pagelist $Title={$:PhQuery} fmt=#local-search-news group=News : )
Первая строка: просто для удобства выносим в переменную обработку, запрос преобразуется с помощью Markup Expressions.
Пример страницы с поисковой формой
(:if false:) PhQuery:"*{(tolower "{$?query}")}*,*{(ucfirst "{$?query}")}*" [[#local-search]] (:template default list=normal order=group,title:) (:template first {=$Group}:) {{=$Group}$Title} (:template each:) [[{=$Group}/{=$Name}|+]] (:template none:) Поиск не дал результатов. [[#local-searchend]] (:ifend:) !%apply=block ph-sandy% {$Title} ---- Словосочетание: (:input form method=get:) (:input search query value="{$?query}" :) (:input submit value="Искать":) (:input end:) (:if !equal {$?query} "":) !!!Коллекция (:pagelist $Title={$:PhQuery} fmt=#local-search:) (:ifend:) (:if [ auth edit && !equal {$?query} "" ] :) >>admin<< Исходный поисковый запрос: {$?query} К выборке: {$:PhQuery} >><< (:ifend:)