Переход от API к SphinxQL и обратно

Какой способ лучше использовать - SphinxQL или API?

Бинарный API

Бинарный API:

  • самый старый способ обращения к серверу Сфинкса
  • реализован на различных языках программирования, в том числе с не официальной поддержкой

Имеет недостатки:

  • дополнительная нагрузка на клиент, связанная с упаковкой и распаковкой данных в двоичный формат
  • клиентская библиотека для работы с API должна соответствовать версии сервера Сфинкса. Использование старой библиотеки с более новым Сфинксом может привести к неправильной интерпретации запроса и отсутствию новых возможностей поиска
  • невозможно менять индексы реального времени

SphinxQL

real-time-fulltext-search-with-sphinx-23-638.jpg

SphinxQL - использует транспортный протокол MySQL 4.1

  • не требует библиотеки API
  • возможно использовать с любым клиентом MySQL
  • SphinxQL - разновидность SQL, похожая на MySQL, но с отличиями

Отличия SphinxQL от MySQL

  • MATCH - не то же самое, что в MySQL
  • SphinxQL имеет часто используемую в запросах опцию OPTION, которой нет в MySQL
  • оператор OR не поддерживается в секции WHERE, но поддерживается в выражениях SELECT
  • возможна поддержка ORM, но требует их доработки
  • есть специальная команда SHOW META, которая вызывается сразу после SELECT и показывает дополнительную информацию (общее количество найденных документов, статистику, а с версии 2.1.1 - статистику по IO и CPU (если searchd запущен с опциями --iostats и --cpustats))
  • SphinxQL - единственный способ обновления RealTime индекса (RT), а также имеет дополнительную функциональность: очистка RT индекса, показ структуры индекса (с DESCRIBE).

API vs SphinxQL

Результаты запроса являются одинаковыми для обоих способов обращения. Основное отличие - некоторые запросы требуют больше определений в SphinxQL (как следствие - больше возможностей настройки).

Например, API имеет несколько режимов matching mode, которых нет в SphinxQL. Режим в SphinxQL такой же, как SPH_MATCH_EXTENDED2 из API.

Сейчас, когда делается запрос по API, внутренне он преобразуется в команду SphinxQL, поэтому режимы matching mode API можно моделировать в SphinxQL:

API matching mode в SphinxQL

Режим matching mode Запрос SphinxQL
SPH_MATCH_ALL SELECT * FROM index WHERE MATCH('one two') OPTION ranker = proximity;
SPH_MATCH_ANY SELECT * FROM index WHERE MATCH('one | two') OPTION ranker = matchany; или
SELECT * FROM index WHERE MATCH('"one two"/1') OPTION ranker = matchany;
SPH_MATCH_PHRASE SELECT * FROM index WHERE MATCH('"one two"') OPTION ranker = proximity;
SPH_MATCH_BOOLEAN SELECT * FROM index WHERE MATCH('one -two') OPTION ranker = none;
SPH_MATCH_EXTENDED и SPH_MATCH_EXTENDED2 SELECT * FROM index WHERE MATCH('one two');
SPH_MATCH_FULLSCAN Полный перебор делается без использования конструкции MATCH

От SphinxQL к API

Пример запроса SphinxQL:

sphinx.sql
SELECT id,user_id FROM myindex 
WHERE MATCH('@title one @content two') AND property_id BETWEEN 10 and 100 
ORDER BY group_id DESC,user_id ASC
LIMIT 10,20 
OPTION ranker=expr('sum(lcs*user_weight+exact_hit)*1000+bm25'), idf=plain, user_weight=(title=100,content=20);

На PHP через API выглядит так:

sphinx.php
$cl = new SphinxClient();
$cl->SetMatchMode(SPH_MATCH_EXTENDED2);
$cl->SetFilterRange('property_id', 10,100);
$cl->SetSortMode(SPH_SORT_EXTENDED,'group_id DESC,user_id ASC');
$cl->SetFieldWeights(array('title' => 100, 'content' =>20));
$cl->SetQueryFlag('idf','plain');
$cl->SetRankingMode(SPH_RANK_EXPR,'sum(lcs*user_weight+exact_hit)*1000+bm25');
$cl->SetSelect('id,user_id');
$cl->Query('@title one @content two','myindex');

От API к SphinxQL

Типичный пример перевода геопозиции из API в SphinxQL:

geo.php
$cl->SetGeoAnchor('latitude','longitude',1.3521,0.3432);
$cl->SetSortMode(SPH_SORT_EXTENDED, '@geodist ASC');
$cl->SetFilterFloatRange('@geodist',0,1000);
$cl->Query('..etc..','myindex');

SphinxQL:

geo.sql
SELECT *, GEODIST('latitude','longitude',1.3521,0.3432) as g FROM myindex WHERE MATCH('..etc..') AND g BETWEEN 0 AND 1000 ORDER BY g ASC;

Мультизапросы SphinxQL

Через API очень удобно сделать пакетный запрос из нескольких простых, который может сработать быстрее из-за механизма оптимизации мультизапросов (используется в фасетном поиске).

multi-queries.php
$cl->SetSortMode ( SPH_SORT_RELEVANCE );
$cl->AddQuery ( "hello world", "myindex" );
$cl->SetSortMode ( SPH_SORT_ATTR_DESC, "price" );
$cl->AddQuery ( "hello world", "myindex" );
$results = $cl->RunQueries();

Результат будет содержать массив с результатами каждого запроса. Кроме того, есть методы ResetFilters() и ResetGroupBy(), которые делают полный сброс уже добавленных фильтров или группировки вызовов.

В SphinxQL также есть мультизапросы, которые запускаются так же, как обычные мультизапросы к MySQL.

В PHP для мультизапросов есть mysqli::multi_query(), запросы пишутся через ;.

Оригинал