0

Я использую библиотеку 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);

Yuriy
  • 333
Jony
  • 1,998

2 Answers2

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
romeo
  • 5,078
  • В Вашем примере конфига составлен один источник, но без указания полей. Так же не ясно, как в выходном массиве определить, из какой таблицы получены ID's – Jony Dec 25 '14 at 21:32
  • из какой таблицы получены

    ...
    sql_query  =  SELECT id, title, 'articles' AS `table` FROM articles WHERE id >= $start AND id <= $end
    
    sql_field_string = table
    ...
    

    Подобное мне приходилось использовать исключительно для UNION-запросов.

    – romeo Dec 25 '14 at 21:54
  • Приведу в вопросе пример своего ресурса, не понимаю до сих пор этот момент – Jony Dec 25 '14 at 22:03
  • У меня таблица определена как: sql_attr_uint = type и почему-то не входит в результат – Jony Dec 25 '14 at 22:05
  • Romeo, может Вас попросить поделиться знаниями о Sphinx, а именно о типах атрибутах sql_attr_uint и прочих основах? – Jony Dec 25 '14 at 22:09
  • @Oleg Ponomarchuk В своём ответе я разместил скрин результата с полем type - всё выводится.

    Вы каким API пользуетесь, нативным (sphinxapi.php)? Приведите код, который Вам выводит массив fields.

    – romeo Dec 25 '14 at 22:50
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".

VasyOk
  • 2,771
  • Спасибо за подробный и качественный ответ! Могли бы Вы привести пример одного из описанных источников в файле sphinx.conf? Чтобы понять, как настроить вывод полей? Сейчас у меня выходной массив от поиска не содержит ничего, чтобы указывало из какой таблицы полученные ID's, нужно хотя бы сделать выходное поле type, фиксированное значениями для каждого запроса. – Jony Dec 24 '14 at 08:31
  • Я заметил, что в результирующий массив от поиска попадают поля, которые описаны в конфиге как: sql_field_string, при этом есть sql_attr_uint = type, которые не попадают в этой массив. – Jony Dec 24 '14 at 08:35
  • https://gist.github.com/VasyOk/9df7614fc6d101d40c2b - жутко старый конфиг, который я написал для теперь уже не работающего сайта, думал, что удалил. – VasyOk Dec 24 '14 at 09:39
  • @VasyOk

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

    Лучше не увлекаться, ибо всё это дело лежит в памяти. Правильной практикой будет хранить поля отличные от string с дополнительный запросом в БД, как, собственно, Вы и отметили выше. Исключением может быть сценарий, при котором необходимо вывести 1-2 поля с ограниченным числом символов (VARCHAR), к примеру, title.

    @Oleg Ponomarchuk Предлагаю посмотреть мой конфиг для актуальной версии Sphinx 2.2.6 https://github.com/romeOz/rock/blob/master/tests/data/sphinx/sphinx.conf

    – romeo Dec 24 '14 at 11:27
  • @Oleg Ponomarchuk Бывают случаи, когда здорово помогает использование sql_attr_multi (MVA). К примеру, если посмотрите на главную http://hashcode.ru/, то заметите, что в каждом сниппете вопроса имеется набор тегов. В случае RDBMS, это как правило связь M:M ("многие ко многим"). Sphinx с этой задачей справится быстрее нежели стандартные средства СУБД (JOIN-ы или несколько запросов). Вот ещё неплохая статейка про MVA. – romeo Dec 24 '14 at 11:48
  • Спасибо! Не совсем понял о: Правильной практикой будет хранить атрибуты отличные от string с дополнительный запросом в БД и как мне определить от какой таблицы получены ID's чтобы сделать в них запрос на выборку? И можно ли этот запрос делать средставами Sphinx, – Jony Dec 24 '14 at 12:07
  • @Oleg Ponomarchuk Написал в виде ответа. – romeo Dec 24 '14 at 15:59
  • Update #2 - все равно не получаю название таблицы в выходном массиве, только названия поля. Запрос: $result = $s->query('mam', '*'); – Jony Dec 26 '14 at 15:09