Данный текст не является переводом с английского, хотя кому-то может так показаться. Описываемый в статье продукт был изначально рассчитан на англоязычную аудиторию, хотя разрабатывается в РФ. И так бывает.
Предыстория
Много лет мы (команда Epsilon Web Manufactory) занимались разработкой сайтов и разных приложений на заказ, в основном это были проекты на базе популярного движка WordPress. И как правило самой сложной и интересной задачей всегда был полнотекстовый поиск. Если на сайте были только статьи и какие-то кастомные типы записей, содержащие заголовок и основной текст, то достаточно было использовать встроенный класс WP_Query
, который с небольшой подстройкой входных параметров отлично справлялся с задачей. Но это было лет 10-12 назад.
Кто не в курсе - нативно WordPress для полнотекстового поиска до сих пор (в 2022 году) использует конструкцию LIKE "%слово%", которая работает, но крайне неэффективно. Выручает тот факт, что все записи (страницы, посты, меню, и т.д. и т.п.) в WordPress хранятся в одной таблице wp_posts
, так что сделать поисковый запрос не так сложно.
По мере того, как WordPress становился более популярным, потребности клиентов также росли. И всё чаще и чаще появлялась необходимость осуществлять поиск не только по заголовкам и тексту статьи, но и по другим немаловажным текстовым данным. Это и мета-данные публикаций, которые хранятся в отдельной таблице, а зачастую их значения ещё и сериализованы, это и таксономии, и другие данные. Обычный WP_Query
уже не вывозил эту задачку. Мы начали делать свои собственные запросы в MySQL и всю обвязку к ним (кастомные формы, кастомные страницы результатов поиска). Потом появился плагин ACF, очень удобный инструмент для прикручивания к записям разных данных и пользователи начали создавать не только блоги, но и сложные приложения, прикручивая всё, что можно прикручивать - файлы, галереи фотографий, тонны кастомных текстовых полей и др.
Пользователям удобно, но для полнотекстового поиска эта ситуация аховая. Теперь простой запрос для поиска по всем этим данным сделать стало невозможно. И если раньше мы применяли всякие "LEFT JOIN" для поиска по мета-полям и таксономиям, то теперь сами данные стали настолько сложными, что LIKE
и даже REGEXP
туда ну никак не прикрутить.
Решение есть - индексированный поиск!
Появилась необходимость в глобальном решении проблемы. Конечно, мы в курсе существования мощных систем поиска вроде Elastic Search, Apache Solr и Sphinx, только вот для WordPress они не всегда применимы. Для них нужен как минимум VPS или аренда облачного сервиса, ну и надо добавить, что из коробки WordPress не умеет с ними работать.
Поэтому мы решили сделать свой собственный плагин, который не требовал бы дополнительных затрат от клиента. Поиск должен работать только с использованием MySQL и PHP - только этим в основе своей располагает WordPress.
Идеально также, если бы плагин не использовал свою точку входа, а заменял стандартный вызов WP_Query
, чтобы другие плагины могли бы воспользоваться новым функционалом.
Сперва мы хотели просто собирать все текстовые данные, по которым планируем искать, в отдельной таблице, и дальше делать по ним LIKE или MATCH AGAINST. Но в конце концов остановились на создании полноценного индекса, состоящего из таблиц слов и векторов. Как показали тесты - этот подход даёт намного большую (в десятки раз) скорость поиска на большом объёме данных (более 100к постов), а кроме того, позволяет реализовать много других функций, например, вычислять релевантность, придавать вес различным публикациям и частям публикаций (например, отдельным мета-полям), да и вообще намного более гибкий.
В целом эта концепция хорошо известна как TF-IDF и широко применяется во всех современных системах полнотекстового поиска (включая вышеупомянутые Elastic Search, Apache Solr, Sphinx и др.).
И ведь действительно, вместо того, чтобы искать слово в огромном массиве текста, можно заранее найти все тексты, в которых конкретное слово встречается, сохранить список этих текстов, а затем, когда кто-то ищет это конкретное слово, просто выдать готовый список. Здорово?
Да, и мы пошли по этому пути.
Шаг 1. Индексирование
В нашем плагине поиск разбивается на два шага. Первый шаг называется "индексирование". Мы последовательно проходим по всем записям WordPress из таблицы wp_posts
, вытаскиваем все тексты, которые прилинкованы к записи (сюда относятся мета-данные, таксономии, тэги и проч.), и полученные данные сохраняем в формате слово-вектор в индексных таблицах. Здесь нужно отметить, что плагин покрыт хуками, и на индексирование также имеется хук wpfts_index_post
, внутри которого программист может помочь плагину подтянуть нужные текстовые данные, связанные с конкретным постом.
Плагин также следит за всеми изменениями, и если какая-то запись в wp_posts
изменяется, то производится инкрементное обновление индекса.
Индексирование происходит в фоновом режиме. Владельцу сайта не приходится что-либо проверять или нажимать время от времени какие-то кнопки. Данные для поиска появляются в индексе спустя 1-2 секунды после обновления данных в публикации.
Ещё раз напомню, что весь поисковый индекс хранится в той же базе данных, что и весь остальной сайт на WordPress. При этом никакие существующие таблицы WordPress не модифицируются.
Шаг 2. Собственно, поиск.
Когда пользователь выполняет стандартный поиск в WordPress, то система вызывает экземпляр класса WP_Query
с параметром "s = поисковая фраза".
Поскольку метод WP_Query
хорошо оснащён хуками, мы контролируем его поведение в той части, где он пытается создать список частей основного запроса для MySQL и делаем так, чтобы вместо стандартного LIKE использовался подзапрос по нашим индексным таблицам. Я не буду тут расписывать подробную логику, поскольку это - самая сложная часть. Напишу лишь, что после того, как от MySQL получен список векторов (то есть пар вида "слово-документ") мы производим дополнительную обработку с помощью кода PHP, чтобы посчитать релевантность. Далее список ID постов вместе со значением релевантности возвращается из WP_Query
и вызывающий код (будь то сам WordPress или какой-то плагин) даже не подозревает, что произошло что-то хорошее.
Немного о вычислении релевантности
Релевантность - очень важный показатель. Именно она определяет, какой из постов будет показан пользователю в топе списка. Именно это определяет качество поиска.
К слову сказать, нативный поиск WordPress определяет релевантность очень просто - каждое найденное слово из фразы добавляет +1 к релевантности. Если во фразе 3 слова, а в тексте поста встретилось только одно из них, то релевантность будет 0,33. Постов с одинаковой релевантностью может быть множество. Поэтому по умолчанию WordPress сортирует результаты поиска просто по дате последнего изменения записи. Как вам такое?
В нашем же плагине реальная релевантность вычисляется на основе множества показателей.
Во-первых, для каждого слова в искомой фразе учитывается степень его совпадения с найденным словом. Так, если мы ищем слово "слон", то у слова "слоновый" будет меньший вес, чем у слова "слоник", а максимальный вес будет у слова "слон".
Учитывается количество повторений слова в одном документе (эта часть известна как "TF") и количество повторений слова во всех документах ("IDF"). Чем больше документов содержит это слово, тем менее значимым в целом оно считается. Таким образом, например, слово "как" в поисковой фразе "устал как конь" будет добавлять наименьший вес к релевантности, поскольку "как" встречается почти во всех документах.
Также учитывается вес слова во фразе. Например, если мы ищем фразу "крепкий кофе", то будут найдены все документы, содержащие оба слова, но релевантность тех документов, где эти слова стоят близко друг от друга будет намного выше. То есть документ с фразой "крепкий чёрный кофе" будет выше, чем "крепкий ароматный чёрный кофе".
На вес документа в выдаче также влияет то, в каком месте документа найдена фраза. В процессе индексирования каждая часть документа попадает в отдельный кластер (например, заголовки попадают в кластер "post_title", основной текст в "post_content" - идентификатор кластера можно выбрать). У каждого кластера есть свой вес от 0 до 1. И этот вес потом учитывается в формуле для релевантности.
Вывод результатов поиска
Стандартный вывод результатов поиска в WordPress тоже никуда не годится. Они просто берут начало основного текста статьи, обрезают 115 символов и выводят это как цитату. Разумеется, нет никакой гарантии, что искомая фраза попадёт в этот кусок и контекст, в котором эта фраза встречается.
Поэтому мы решили переделать и эту часть. Для основы взяли вывод результатов поиска в Google Search, который выбирает из текста отдельные предложения, в которые входит поисковая фраза, подрезает их немного (если они слишком длинные) и составляет их них поисковую цитату. Мы назвали это "Smart Excerpts".
На наш взгляд, получилось неплохо. Клиенты тоже довольны. Кроме всего прочего, в качестве основы для построения цитаты используется весь текстовый массив, который попадает в индекс, а не только основной текст статьи.
Что ещё реализовано
Кроме того, что описано выше, плагин уже поддерживает
Технологию WordPress Multisite.
Возможность использовать OR и AND логику.
Выбор способа сортировки результатов (по релевантности, дате, ID, количеству комментариев и т.д.).
"Живой поиск" Live Search с помощью виджета поиска, которым надо заменить стандартный.
Поиск внутри шоткодов (shortcode) и Gutenberg-блоков.
Поиск медиа-файлов и файлов, прилинкованных к публикациям, по текстовому содержимому файлов (поддерживаются PDF, DOC, DOCX, XLS, XLSX, RTF и многие другие форматы) - для извлечения текста мы используем свой собственный микро-сервис.
Что планируется добавить в ближайшем будущем
Подробную и исчерпывающую документацию по всем хукам и принципу работы.
Поддержку логических выражений в запросе ("чёрный кофе" OR "чай с молоком" OR ("кефир" AND "огурец")).
Возможность добавлять таблицы синонимов.
Возможность добавлять таблицы стоп-слов.
Автоматическую стемизацию запроса (когда вместе с запрошенным словом "слоник" будет искаться и "слон" и "слоновый").
Поиск изображений по EXIF и тексту, найденному на них (ага, OCR).
Конструктор запросов и фильтров (что позволит добавлять несколько разных видов поиска на один сайт).
Конструктор индекса (чтобы не добавлять правила индексирования через код, а легко делать это через админку).
...планов громадьё!
Ресурсы
Плагин совершенно бесплатен, он регулярно обновляется в репозитории WordPress
Также есть его платная версия (в которую включена поддержка поиска файлов по содержимому и персональная техническая поддержка), которую можно приобрести на официальном сайте WP FullText Search Pro.
Вы можете купить Pro версию просто для того, чтобы поддержать разработку плагина, поскольку на его разработку уходит масса времени и лишняя денежка точно не помешает.
Ваши комментарии и рекомендации помогут нам сделать продукт ещё лучше. Спасибо, что дочитали до конца.
Комментарии (36)
expdxx
14.07.2022 02:06А как определяется относительная релевантность слов "слоник" и "слоновый", например? По тому, сколько символов есть в слове помимо основного для нас "слон" ?
И как вы поступаете со словами, которые имеют несколько значений? К примеру, "мышь полевка" и "компьютерная мышь" - 2 совершенно разных кейса использования слова "мышь". И если пользователь искал "проводная мышь", то не совсем очевидно, какой из результатов будет более релевантным.
Epsiloncool Автор
14.07.2022 02:18Относительная релевантность слова на данный момент определяется просто по длине. Длина искомого слова делится на длину найденного слова (получается всегда меньше 1) и это как раз является коэффициентом релевантности слова.
Сейчас алгоритм не различает смыслов слов. Если по запросу "мышь" пользователь будет получать "мышь полёвка", то он сможет уточнить запрос добавлением "комп" или "прово", что уже однозначно выдаст искомый результат.
vshemarov
14.07.2022 08:44+2Немного смущает термин "быстрый" в заголовке. Если я верно понял из описания, то алгоритм, в целом, такой:
1) разбиваем поисковую строку на слова
2) находим записи по каждому слову из поиска
3) по всем найденным записям вычисляем релевантность
4) дергаем из базы записи в соответствии с релевантностью
Звучит все просто и логично (возникло даже желания в одном из своих проектов такой подход попробовать). Но насколько быстро это работает на больших объемах? Ведь п.2 может вернуть овердофига записейFanatPHP
14.07.2022 09:05Ну я так прикинул, если делать первичную выборку релевантности прямо в запросе, то должно получиться норм. Скажем, та самая степень совпадения и общий вес слова легко учитываются в запросе. Да и общий вес фразы, через group by + having. Вот жалко что именно таких подробностей в посте нету. Такое ощущение, что пост написан не на Хабр, а на сайт с плугинами для вордпресса, чисто инструкция по использованию.
Epsiloncool Автор
14.07.2022 13:09Действительно, п.2 может вернуть очень много записей. Но, к счастью, это очень короткие записи (каждая содержит только ID слова и ID документа), и это ничего, если их будет пара-тройка миллионов, PHP сегодня быстр и такие данные обрабатывает влёт. Всё-таки самая долгая операция в этом алгоритме - запрос к MySQL, поэтому он максимально простой.
FanatPHP
14.07.2022 14:02Мне кажется, про пару-тройку миллионов вы несколько эээ… преувеличили. В статье упоминается база с сотней тысяч постов — такая цифра будет ближе к реальности при таком-то варварском подходе. Но на то чтобы зафетчить в 20-30 раз больше, понадобится минимум секунда. А это уже неприемлемо для быстрого поиска. Не говоря обо всех последующих сортировках, нагрузке на канал и прочем.
Epsiloncool Автор
14.07.2022 14:38Всё очень индивидуально на самом деле. Зависит от мощностей сервера на котором крутится MySQL, от размеров RAM и innodb_cache в частности. На практике мы получали результаты менее секунды при 400к постов, правда там и сервер не самый плохой - 16 Гбт памяти, MySQL настроен как нужно, 2048 Mb отдано под php memory_limit. Опять же хочу добавить, что алгоритм не ставит целью победить по скорости современные поисковые системы. Тут речь про инструмент, нативно работающий под WordPress.
FanatPHP
14.07.2022 14:54Ну об этом я и говорю. 400к — это на порядок меньше заявленных выше "пары-тройки миллионов".
И дело тут не в конкуренции с поисковиками. А в пределе, на котором эта система загнётся. Просто в силу неоптимальной архитектуры. При том что могла бы ещё работать, на том самом копеечном хостинге, ради которого всё и затевалось :)
Epsiloncool Автор
15.07.2022 00:31400k - это записей. А векторных пар при этом получается несколько миллионов, потому что слова встречаются в документах по нескольку раз.
Если у вас есть рекомендации по оптимизации кода или алгоритма (или полной перестройке системы, если старую не починить), то поделитесь. Свежие идеи со стороны - это всегда хорошо.
Хостинг не обязательно должен быть копеечный. Порой владельцы сайтов не используют мощные поисковые решения (и мощные современные движки для создания сайтов) совсем по другим причинам. Среди наших клиентов есть весьма небедные владельцы новостных порталов и онлайн-библиотек, которые продолжают пользоваться WordPress.
FanatPHP
14.07.2022 08:47Ну то есть вы сделали такой полнотекстовый поиск на коленке, который чисто технически — это
keyword like 'слово1%' or keyword like 'слово2%'
и дальше всякая уличная магия по вычислению релевантности. Мне кажется, это полезно было бы упомянуть в статье. Так она станет ближе к читателю, которому всегда интереснее узнать, как работает некая штуковина, а не какие молодцы её создатели ;)Не очень понятно, за счет чего достигается большая скорость, если встроенный полнотекстовый действует практически так же. Или MATCH AGAINST там случайно при построении фразы затесалось? :)
Есть ли первичный отбор по релевантности в запросе? Мне кажется, он должен быть, иначе придется на РНР перерабатывать много мусора. Вы же ограничиваете выборку?
gnome2_terminal_is_best
14.07.2022 12:43При желании, можно поизучать код. Там не так много файлов. Один из недостатков, по моему, это зависимость от внешнего сервиса (микросервиса) (fulltextsearch.org/fire), который получает post-запрос с чем то, отдаёт что то.
FanatPHP
14.07.2022 12:46Хм. Как-то странно. А этот микросервис точно нужен? Это же явно не внешний поисковик. Может быть, просто защитка/собиралка персональных данных?
gnome2_terminal_is_best
14.07.2022 13:58Там написано в тексте про это:
Поиск медиа-файлов и файлов, прилинкованных к публикациям, по текстовому
содержимому файлов (поддерживаются PDF, DOC, DOCX, XLS, XLSX, RTF и
многие другие форматы) - для извлечения текста мы используем свой
собственный микро-сервис.FanatPHP
14.07.2022 14:10А, ну так это файло. При чём оно здесь? В статье-то речь идёт про поиск по базе. Плюс извлечение текста нужно только для индексирования, а для поиска-то оно зачем?
gnome2_terminal_is_best
14.07.2022 14:12Ну, хотя бы, чтобы можно было индексировать, содержимое файлов.
Epsiloncool Автор
14.07.2022 14:18+1Для разбора файлов мы используем свой собственный сервис Textmill.io. В бесплатной версии (которая в репе WordPress) нет этого функционала, он есть только в платной версии.
Но для гика всё просто на самом деле - при индексировании каждого поста WP вызывается хук wpfts_index_post, и мы можем проверить тип поста. Если он "attachment", то есть медиафайл, то мы берём ссылку на файл, передаём его в Textmill.io, в ответ получаем разобранный файл в виде JSON, который уже индексируем как обычный текст.
Кстати в платной версии встроена библиотека для разбора PDF на PHP. Работает она неплохо, но очень большие файлы не тянет. Так что если у клиента есть необходимость искать только PDF, он может поставить побольше memory_limit, отключить Textmill.io и пользоваться только внутренним экстрактором.
Epsiloncool Автор
14.07.2022 14:17+1Это микросервис fire-flare. На поиск он не влияет и единственный его смысл в том, чтобы уведомлять фронтенд о происходящих на сервере (внутри индексатора) событиях. Всё может работать и без этого микросервиса, но тогда приходится периодически (довольно часто, 1 раз в 5 секунд) делать запросы с клиента на сервер WP, отчего сильно увеличивается загрузка, особенно если открыто 10 вкладок одной и той же админки.
Зачем уведомлять фронтенд? В админке есть блок статистики, показывающий текущее состояние индекса (сколько документов проиндексировано, сколько в очереди и всё такое прочее) - эта информация динамично меняется и хотелось бы обновлять её 1 раз в 5 секунд хотя бы. Вот для того, чтобы не мучать WP мы и сделали такой внешний ретранслятор коротких информационных пакетов.
Epsiloncool Автор
14.07.2022 14:11Первичного отбора по релевантности нет, нам показалось логичным, что право на попадание в список результатов могут получить абсолютно все документы, даже те, в которых есть одно-единственное малорелевантное слово. Таким образом, выборка векторов производится абсолютно по всем совпадениям.
Одна из операций выборки - это получение полного списка подходящих слов из таблицы слов. Тут используется LIKE 'слово%' либо LIKE '%слово%' (в зависимости от режима работы - есть два режима "простой поиск" и "глубокий поиск"). Но такой способ использования LIKE использует ключи, поэтому он очень быстр. А вот полнотекстовый поиск с использованием LIKE 'слово%' невозможен, потому что он будет искать слово только в начале текста, а в середине текста находить не будет. Поэтому в WordPress нативно используется только LIKE '%слово%', который ключи не использует и поэтому крайне медленный на больших объёмах данных.
Отдельно могу сказать по MATCH AGAINST. Да, скорее всего внутри MySQL используется похожий принцип, вот только настроить этот поиск никак невозможно. Есть несколько параметров внутри глобального конфига my.ini/my.cnf, которыми можно задать, например, минимальную длину слова (она по умолчанию выставлена в 3), то есть слова короче 3 символов просто игнорируются, независимо от их важности. Релевантность он считает по каким-то своим формулам. Изменить глобальный конфиг через PHP тоже не получится на большинстве хостингов.
И да, тесты показали, что MATCH AGAINST работает медленно на больших массивах. Наш алгоритм быстрее.
Я планирую в ближайшее время написать ещё одну статью с детальным разбором алгоритма релевантности и проведу сравнение с нативным LIKE-поиском и вариантом с MATCH AGAINST. Не хотелось перегружать обзорную статью техническими деталями.
FanatPHP
14.07.2022 14:39Спасибо за подробный комментарий!
С поиском тут небольшая путаница. Сначала вы пишете что
LIKE '%слово%'
использует индекс, а чуть ниже — что не использует. Я думаю, в первом случае вы имели в виду, что поле целиком лежит в оперативке, то есть даже полный перебор будет быстрее, чем на диске — и в этом смысле наличие индекса ускоряет поиск. Но, всё-таки, в общепринятом смысле — практически мгновенный бинарный поиск за считанное количество переходов — индекс тут не используется.Логику с одним-единственным малорелевантным словом я, честно говоря, не понял. Если результатов мало, то это слово и так попадёт. Если результатов много — то при сортировке это слово всё равно окажется в самом конце списка, и его никто не увидит. Я честно не понимаю, какой смысл его оставлять в больших выборках. Как-то мне идея с сортировкой на клиенте совсем не нравится. И по скорости, и по памяти. В конце концов, исходным посылом была забота про дешевые хостинги, а тягать из базы по 15-20 мегабайт на каждое нажатие клавиши даже и на дедике не кажется мне хороший идеей.
Буду с нетерпением ждать вторую статью.
Epsiloncool Автор
14.07.2022 15:45Должен разъяснить. Дело в том, что MySQL по-разному оптимизирует LIKE в зависимости от того, какой параметр используется для поиска. Если LIKE используется без % в начале (например, LIKE 'слово%'), то MySQL будет использовать ключ фиксированного размера на соответствующем поле VARCHAR.Поэтому такая выборка работает очень быстро - не нужно ничего искать, MySQL уже знает, в каких строках таблицы слов находятся подходящие слова. Поэтому такой LIKE смело можно назвать не поиском, а выборкой по ключу. И по сути индексированный поиск WP FullText Search - это тоже не поиск, а выборка по ключу :-) поэтому и быстрый.
Если же LIKE используется с % в начале параметра (например, LIKE '%слово%'), то использование ключа становится невозможным. MySQL приходится проверять весь текст полностью, сравнивая '%слово%' со строкой в цикле. И это уже реальный поиск.
Есть немного информации тут
https://stackoverflow.com/questions/2042269/how-to-speed-up-select-like-queries-in-mysql-on-multiple-columnsСовсем неочевидно, сколько ещё будет результатов кроме одного найденного малорелевантного. Может быть десяток, а может быть, этот результат будет вообще один-единственный. Во всяком случае, мы не можем решать за пользователя, хочет ли он просмотреть все найденные документы или ему достаточно лишь 30% от найденного. Бывает, что запрос сложный.
Про сортировку на клиенте речи не было. Весь поиск, сортировка и генерация страницы с результатами поиска производится на стороне PHP, то есть, на сервере.
Нет ничего плохого гонять большие объёмы информации. Это бесплатно. В отличие от аренды VPS с root-доступом и программистом, который может всё настроить, или облачного решения для поиска. Хотя многие склоняются к такому варианту и вполне счастливы.
FanatPHP
14.07.2022 16:09Это-то понятно, просто в комментарии выше у вас написано немного противоположное:
Тут используется LIKE 'слово%' либо LIKE '%слово%' (в зависимости от режима работы — есть два режима "простой поиск" и "глубокий поиск"). Но такой способ использования LIKE использует ключи, поэтому он очень быстр.
Видимо, вы просто тут оговорились. Хотя не очень понятно, что в итоге хотели сказать.
мы не можем решать за пользователя, хочет ли он просмотреть все найденные документы или ему достаточно лишь 30% от найденного
Смотрите, у вас типичная проблема, туннельное зрение. Вы забываете контекст. А контекст — я напомню — "пара-тройка миллионов" результатов. И в этом контексте вы прекрасно знаете, хочет пользователь просмотреть их все, или нет. Особенно если речь о живом поиске.
В отличие от аренды VPS с root-доступом и программистом, который может всё настроить
Ну то есть у вас такого программиста не нашлось, и вы переложили сортировку с SQL на РНР? Теперь понятно.
Нет ничего плохого гонять большие объёмы информации.
Проблемы никакой нет, но я вам советую не слишком громко об этом говорить. Могут программисты услышать.
Epsiloncool Автор
14.07.2022 16:16На каждую реплику у меня есть логичный ответ, но я предпочту не отвечать, чтобы не продолжать общаться в подобном тоне.
FanatPHP
14.07.2022 16:28+1Не переживайте, рекламный пост на Хабр — чек. А то что в нем всё с ног на голову, индексы в своих запросах используются, а в чужих — нет, а гордое "в десятки раз" вдруг превращается в скромное
летают, но низенько-низенько"наш алгоритм быстрее" — ну кто ж считает-то.
FanatPHP
14.07.2022 09:21+1И ещё конечно бесит это пещерное "Download". В 2022, чтобы посмотреть код его надо скачивать на компьютер, разворачивать, вот это вот всё — серьёзно? Ещё и хаб "Open source". Тут скорее бы подошёл хаб "Shareware". Непонятно, кстати, почему нет репозитория в открытом доступе. Ведь он по идее должен быть. Но получается, что приватный. Какой-то такой получается Open source с душком.
gnome2_terminal_is_best
14.07.2022 14:06Во вкладке "Development", есть ссылка на просмотр кода "Browse the code".
Epsiloncool Автор
14.07.2022 14:27Можно скачать напрямую из репозитория WordPress, он в открытом доступе
olku
14.07.2022 15:49+1Есть еще файловый Хapian с 30-летней историей. Был весьма хорош для прототипов и однонодных решений, но биндинг остался с PHP5, увы.
gnome2_terminal_is_best
15.07.2022 00:01
gnome2_terminal_is_best
Хорошая работа и фича. А за какое время, пилили первый рабочий вариант?
Epsiloncool Автор
Первая версия, которую зарелизили и "показали миру" была очень простая, хотя уже имела функционал индексирования. Там была куча багов и вообще непонятно как люди качали и пользовались. Время разработки от идеи до первого релиза было, думаю, месяца три-четыре.
gnome2_terminal_is_best
Круто. А поиск битрикса, не пробовали улучшить? Или им вообще не занимаетесь?
Epsiloncool Автор
Пока, увы, до битрикса не дошли руки.
gnome2_terminal_is_best
Можете это рассматривать, как преимущество)