Еще раз о логике работы Sphinx

Рейтинг: 0Ответов: 2Опубликовано: 24.12.2014

Я использую библиотеку PHP для сфинкса. Написал несколько источников в конфигурации sphinx.conf (статьи, новости, заметки).

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

Дальше мне что, нужно создать отдельный запрос по этим полученным ID для каждой из таблиц? Чтобы отобразить результат пользователю?

Но если выходной массив будет содержать более 1000 различных идентификаторов? Это будет 1000 запросов к БД? Большое спасибо за любой замечание или объяснения!

Один из источников описан так:

source users : lsParentSource
{

    sql_query_range   = SELECT MIN(idDetailToUsers), MAX(idDetailToUsers) FROM detailtousers
    sql_range_step    = 128
    sql_query         = SELECT idDetailToUsers as id, 9 as type, UsersTypeAccount, idDetailToUsers, SpecializationName, DetailToUsersName, DetailToUsersPhoto, city, country FROM detailtousers join users ON users.idUsers = detailtousers.idDetailToUsers left join usersspecialization ON usersspecialization.UsersSpecializationIdUser = detailtousers.idDetailToUsers left join specializationtousers ON specializationtousers.idSpecialization = usersspecialization.UsersSpecializationIdSpecialization WHERE idDetailToUsers >= $start AND idDetailToUsers <= $end GROUP BY idDetailToUsers

    sql_attr_uint     = type
    sql_attr_uint     = idDetailToUsers
    sql_attr_uint     = UsersTypeAccount
    sql_field_string  = SpecializationName
    sql_field_string  = DetailToUsersName
    sql_field_string  = DetailToUsersPhoto
    sql_attr_uint     = city
    sql_attr_uint     = country

    sql_query_info    = SELECT idDetailToUsers, DetailToUsersName, UsersTypeAccount, SpecializationName, DetailToUsersPhoto, city, country \
                        FROM detailtousers WHERE idDetailToUsers = $id
    sql_ranged_throttle = 0
}

Если указать по Вашему примеру - то в выходном массиве я получаю название поля type:

 ["fields"]=>
  array(4) {
    [0]=>
    string(4) "type"
    [1]=>
    string(18) "specializationname"
    [2]=>
    string(17) "detailtousersname"
    [3]=>
    string(18) "detailtousersphoto"
  }

Но без типа(указания на таблицу) Articles

Пользуюсь расширением для PHP(PECL) Sphinx.

Код:

$s = new SphinxClient; $s->setServer("localhost", 9312);

$s->setMaxQueryTime(9000);
$s->setMatchMode(SPH_MATCH_ANY);
//$s->setFilter('type', array( 9, 10) );

$result = $s->query($_POST['search'], '*');
var_dump($result);

Ответы

▲ 2Принят

На самом деле то, что вами описано выше, в принципе рабочий вариант. Да, будет 1000, и вы будете работать с этой тысячей. Но только не нужно забывать про постраничную навигацию (и про то, что дальше 10-й заходят только ради "полистать" и их в принципе можно исключить), и тысячу запросов не нужно делать, все можно сделать одним запросом:

SELECT * FROM TableName WHERE id IN (4,9,6,2...)

Однако, чтобы сохранить релевантность, нужно чтобы этот порядок айдишников вывелся в том же порядке, что он был отдан sphix`ом. Для этого немного sql-магии:

SELECT * FROM TableName WHERE id IN (4,9,6,2...) ORDER BY FIELD (id, 4,9,6,2...)

Но я за время работы с sphinx`ом приобрел собственную (а может, и нет) точку зрения работы с ней.

Sphinx позволяет хранить данные для вывода (агрегирование данные), как по тем полям, что делается поиск, так и по тем полям, что поиск не делается. Поэтому можно sphinx.conf настроить так, чтобы он вместе с id отдавал и другие поля - title, category_name, tags_name и т.д. и т.п. Страница результата поиска не требует подключения к БД в принципе. И у нас появляется возможность сделать крутой "autocomplete".

▲ 3

К примеру, нам нужно создать индекс по статьям (articles_index):

  • Пример конфига.
  • Убиваем демон, который запустился после установки Sphinx: sudo service sphinxsearch stop
  • Создаём индекс: sudo indexer --config /path/to/sphinx.conf --all

Ошибок быть не должно. Разве что: WARNING: Attribute count is 0: switching to none docinfo и WARNING на common_source - не обращаем внимание.

  • Запускаем демон: sudo searchd --config /path/to/sphinx/sphinx.conf
  • Коннектимся: mysql -h0 -P9306

    -h0 - это localhost. -P9306 - порт, на котором весит Sphinx демон.

  • Запрос в синтаксисе SphinxQL: SELECT * FROM articles_index WHERE MATCH('тест'); Получаем массив id-ков.
  • Собственно полученные id-ки вставляем в запрос SELECT * FROM articles WHERE id IN (4,9,6,2...), если нужно с соблюдением порядка, то: SELECT * FROM articles WHERE id IN (4,9,6,2...) ORDER BY FIELD (id, 4,9,6,2...)

Как видно, мы делаем два запроса: к демону Sphinx (индекс articles_index), а потом к СУБД (таблица articles).

и как мне определить от какой таблицы получены ID's.

Думаю, я ответил на Ваш вопрос.

И можно ли этот запрос делать средставами Sphinx

Из коробки Sphinx предостаялет API для различных языков, в том числе и для PHP. Как правило, все API хранятся /usr/share/sphinxsearch/api/. Копируйте sphinxapi.php в свой проект и подключаете. Пример использования API. Будьте внимательнее, статья за 2010 год. Актуальная информация по API. Я лично пользуюсь расширением для Yii2, вернее данное расширение я внедрил в свой Rock Framework с некоторыми изменениями.

Если Вы имели в виду, может ли Sphinx, получив ID's, самостоятельно делать запрос в СУБД - нет. Его задача индексация (делает порционный запрос к СУБД и складывает всё в индекс на диск, а некую часть держит в памяти - горячие данные индекса. Про RT-индексы с полноценным CRUD другая история) и поиск с выдачей ID's. В некоторых случаях, возможно, потребуется вывести и другие атрибуты (писал в комментариях).

Update #1

Результат в консоли:

alt text

Update #2

Вот результат использования sphinxapi.php (аналог PECL). Конфиг sphinx.conf. Как Вы могли заметить, результат поиска размещён в matches.

Некоторые замечания:

  • Если matches отсутствует, значит ничего не найдено по Вашему запросу.

Вместо $_POST['search'] укажите "ручками" поисковый запрос.

  • После любых изменений в sphinx.conf требуется переиндексация: sudo indexer --config /path/to/sphinx.conf --all --rotate.
  • При использовании API (если конкретнее, то метода SphinxClient::setMatchMode()) мною замечена ошибка вида Deprecated: DEPRECATED: Do not call this method or, even better, use SphinxQL instead of an API. Как бы авторы в лице Аксёнова и Co намекаю, что использование API на текущий момент времени не является хорошей практикой. Используйте SphinxQL через обыкновенное PDO, а именно: http://pastebin.com/UABtVzys