image

Добрый день, хаброжители!

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

Подробности реализации и ссылка на репозиторий под катом.

Предисловие


В одном крупном web проекте потребовалось использование полнотекстового движка Sphinx. И все бы хорошо, если бы не потребовалось результаты запросов от Sphinx дополнительно сортировать по хитро заданным правилам внутри базы.

И тут встал очевидный вопрос: как? Тут напрашиваются как минимум два варианта:

  • Делать полнотекстовый запрос в Sphinx, результаты сортировать в приложении;
  • Воспользоваться мощью SQL в PostgreSQL для получения данных поисковых запросов из Sphinx в табличной форме с возможностью дополнительной обработки в базе.

Взвесив все плюсы и минусы указанных вариантов, было реализовано расширение sphinxlink. Идея реализации была честно подсмотрена с расширения dblink.

Функции расширения и детали реализации


Как и в dblink, управление всем осуществляется с помощью SQL функций, написанных на C.
Клиентский протокол взаимодействия с Sphinx соответствует протоколу взаимодействия mysql, а это значит, что мы можем использовать самую обыкновенную библиотеку mysql-client для подключения к Sphinx.

Для подключения к серверу Sphinx используется функция sphinx_connect():

SELECT * FROM sphinx_connect('myconn');
 sphinx_connect
----------------
 OK
(1 строка)

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

Для просмотра списка открытых соединений с Sphinx и параметров подключения используется функция sphinx_connections():

SELECT * FROM sphinx_connections();
 conname |   host    | port
---------+-----------+------
 myconn  | 127.0.0.1 | 9306
(1 строка)

А теперь, как отправлять поисковые запросы и получать результаты.

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

Например, создадим индекс в Sphinx со следующей структурой:

DESC myindex;
+---------+--------+
| Field   | Type   |
+---------+--------+
| id      | bigint |
| content | field  |
| title   | string |
+---------+--------+

В поле content будут лежать тексты документов (например, рассказы А.П. Чехова), в поле title — название рассказа, поле id — идентификатор текста (служебное поле в Sphinx).

SELECT * FROM sphinx_query('myconn', 'SELECT weight(), * FROM myindex WHERE MATCH(''красота'')') AS (weight integer, docid integer, title text);
 weight | docid | title
--------+-------+-------
   1680 |     3 | Дома
(1 строка)

Для запроса метаинформации по последнему запросу используется функция sphinx_meta():

SELECT * FROM sphinx_meta('myconn');
   varname   | value
-------------+--------
 total       | 1
 total_found | 1
 time        | 0.000
 keyword[0]  | красот
 docs[0]     | 1
 hits[0]     | 1
(6 строк)

Данная функция сделана для удобства. Аналогичного эффекта можно добиться, послав запрос SHOW META с помощью функции sphinx_query().

Для закрытия ненужного соединения используется функция sphinx_disconnect():

SELECT * FROM sphinx_disconnect('myconn');
 sphinx_disconnect
-------------------
 OK
(1 строка)

Планы реализации


У текущей реализации модуля есть ряд недостатков:

  • Параметры подключений не сохраняются при завершении сессии PostgreSQL — хотелось бы иметь режим работы, при котором параметры соединения сохранялись в реальную таблицу с целью их получения;
  • Все описанное справедливо для запросов на чтение индексов Sphinx, но нет функции управления RT индексами;
  • Ваши предложения?

Традиционно для подобных постов, оставляю ссылку на github: sphinxlink.

Комментарии и предложения горячо приветствуются. Спасибо за внимание!

Комментарии (2)


  1. andy128k
    31.01.2018 13:18

    1. dimv36 Автор
      31.01.2018 13:57

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