Sphinx vs. MySql - поиск по списку друзей (эффективность/скорость)

Я переношу свои запросы приложений на Sphinx из MySQL и мне сложно определить этот вариант, или даже если его вообще нужно портировать (я действительно хочу знать, стоит ли использовать sphinx для этого конкретного для эффективности/скорости):

users
uid uname
  1    alex
  2    barry
  3    david

friends
uid | fid
  1     2
  2     1
  1     3
  3     1

Подробности:
- InnoDB
- пользователей: индекс на uid, index on uname
- друзья: объединенный индекс на uid, fid

Обычно для поиска всех друзей alex с помощью mysql:

$uid = 1
$searchstr = "%$friendSearch%";
$query = "SELECT f.fid, u.uname FROM friends f 
          JOIN users u ON f.fid=u.uid
          WHERE f.uid=:uid AND u.uname LIKE :friendSearch";
$friends = $dbh->prepare($query);
$friends->bindParam(':uid', $uid, PDO::PARAM_INT);
$friends->bindParam(':friendSearch', $searchstr, PDO::PARAM_STR);
$friends->execute();

Насколько эффективнее найти друзей alex с sphinx vs mysql или это будет излишним?
Если sphinx будет быстрее для этого, так как список попадает в тысячи людей, как выглядит запрос индексирования? Как я могу удалить дружбу, которая больше не существует с помощью sphinx, могу ли я иметь подробный пример в этом случае? Должен ли я изменить этот запрос на использование Sphinx?

Ответы

Ответ 1

Хорошо, вот как я вижу, что это работает.

У меня такая же проблема с MongoDB. MongoDB "предлагает" возможности поиска, но так же, как MySQL, вы никогда не должны использовать их, если не хотите, чтобы вас забивали проблемы с IO, CPU и памятью и вы вынуждены использовать гораздо больше серверов, чтобы справляться с вашим индексом, чем обычно.

Вся идея использования Sphinx (или другой технологии поиска) заключается в снижении стоимости на сервер с помощью поискового индексатора.

Sphinx, однако, не является механизмом хранения. Не так просто запросить точные отношения между таблицами, они немного переработали это с помощью SphinxQL, но из-за характера полного текстового индекса он по-прежнему не выполняет интегральное соединение, как в MySQL.

Вместо этого я бы сохранил отношения внутри MySQL, но имел индекс "пользователей" в Sphinx.

На моем сайте у меня лично есть 2 индекса:

  • main (домашние пользователи, видео, каналы и плейлисты)
  • help (справочный системный поиск)

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

Обратите внимание на то, чтобы обрабатывать удаления, а что не ваша коллекция Sphinx через delta, вам понадобится killlist и некоторые фильтры для вашего дельта-индекса. Вот пример из моего индекса:

source main_delta : main
{
    sql_query_pre = SET NAMES utf8
    sql_query_pre =
    sql_query = \
        SELECT id, deleted,  _id, uid, listing, title, description, category, tags, author_name, duration, rating, views, type, adult, videos, UNIX_TIMESTAMP(date_uploaded) AS date_uploaded \
        FROM documents \
        WHERE id>( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 ) OR update_time >( SELECT last_index_time FROM sph_counter WHERE counter_id=1 )

    sql_query_killlist = SELECT id FROM documents WHERE update_time>=( SELECT last_index_time FROM sph_counter WHERE counter_id=1 ) OR deleted = 1
}

Этот процесс удаляет и добавляет раз в минуту, что довольно реально в реальном времени для реального веб-приложения.

Итак, теперь мы знаем, как хранить наши индексы. Мне нужно поговорить об отношениях. Sphinx (даже если он имеет SphinxQL) не будет делать интегральных объединений по данным, поэтому я лично рекомендую делать отношения за пределами Sphinx, не только это, но, как я сказал, эта таблица отношений будет получать большую нагрузку, поэтому это может повлиять на Индекс Сфинкса.

Я бы сделал запрос, чтобы выбрать все идентификаторы, и используя этот набор идентификаторов, используйте метод "фильтр" в API-интерфейсе sphinx для фильтрации основного индекса до определенных идентификаторов документов. Как только это будет сделано, вы можете обыскать в Сфинксе как обычно. Это самый эффективный метод, который я нашел на сегодняшний день для этого.

Ключевым моментом, который следует помнить во все времена, является то, что Sphinx - это технология поиска, а MySQL - технология хранения. Имейте это в виду, и вы должны быть в порядке.

Изменить

Как сказал @N.B(что я забыл в своем ответе) Sphinx действительно имеет SphinxSE. Несмотря на приматовку и все еще в какой-то стадии тестирования ее разработки (то же самое, что и в реальном времени), она предоставляет реальное хранилище типа MyISAM/InnoDB для Sphinx. Это круто. Однако есть оговорки (как и в любом случае):

  • Язык является примитивным.
  • Соединения являются примитивными

Однако он может/может выполнять работу, которую вы ищете, поэтому обязательно загляните в нее.

Ответ 2

поэтому я собираюсь пойти и рассказать о том, что -I- считают, что наилучшие варианты использования для sphinx есть, и вы можете решить, более или менее он подходит для того, что вы хотите сделать.

Если все, что вы хотите сделать, это поиск по строкам одного поля; то с MySQL вы можете выполнять поиск по диким картам без особых проблем и настойчиво с индексом на нем, если вы не ожидаете, что миллионы строк вы будете в порядке.

Теперь возьмите facebook, это не только индексирование имен, но и ect страниц или даже любые расширенные поля поиска. Sphinx может принимать x столбцов из MySQL, PostGRES, MongoDB (вставьте свой db, который вы здесь хотите) и создайте для полнотекстового индекса для всех.

Пример:

У вас есть 5 полей (номер дома, улица, город, штат, почтовый индекс), и вы хотите выполнить полный текстовый поиск по всем этим. Теперь с MySQL вы можете выполнять поиск на каждом из них, однако с помощью sphinx вы можете объединять их все вместе, а сфинкс делает некоторые потрясающие статистические данные на основе строки, в которой вы прошли, и совпадений, которые являются результатом этого.

Эта ссылка: PHP Sphinx Search отлично справляется с тем, что вы увидите, как это будет выглядеть и как все будет работать.

Итак, вы действительно не заменяете базу данных; вы просто добавляете к нему специальный демон (sphinx), который позволяет создавать специализированные индексы и запускать полные текстовые запросы против него.

Ответ 3

Ни один индекс не может помочь вам в этом запросе, так как вы ищете строку как инфикс, а не префикс (вы ищете '%friendname%', а не 'friendname%'.

Кроме того, решение LIKE приведет вас к углам: предположите, что вы искали друга под названием Ann. Выражение LIKE также будет соответствовать Марианне, Дэнни и т.д. В выражении LIKE нет понятия "полное слово".

Реальное решение - использовать текстовый индекс. Индекс FULLTEXT доступен только на MyISAM, а MySQL 5.6 (а не GA в это время) вводит FULLTEXT на InnoDB.

В противном случае вы можете использовать Sphinx для поиска текста.

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

Я использую Sphinx много, на десятках, а иногда и на сотнях миллионов больших текстов, и могу засвидетельствовать, что это работает как шарм.

Проблема с Sphinx, конечно же, является внешним инструментом. С Sphinx вы должны сказать ему, чтобы читать данные из вашей базы данных. Вы можете сделать это (используя crontab например) каждые 5 минут, каждый час и т.д. Поэтому, если строки DELETE d, они будут удалены только из сфинкса при следующем чтении данные из таблицы. Если вы можете жить с этим - это самое простое решение.

Если вы не можете, в sphinx есть индексы реального времени, поэтому вы можете напрямую проинструктировать его об удалении определенных строк. Я не могу объяснить все в этом порту, так что вот пара ссылок для вас:

Обновления индексов

Показатели реального времени

В качестве окончательного вывода у вас есть три варианта:

  • Опасьте это и используйте полное сканирование таблицы, предполагая, что у вас не будет высокой нагрузки.
  • Подождите MySQL 5.6 и используйте FULLTEXT с InnoDB.
  • Использование sphinx

В этот момент я обязательно воспользуюсь опцией № 3: используйте sphinx.

Ответ 4

Взгляните на решение, которое я предлагаю здесь: fooobar.com/info/348157/...

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

Это даст вам быстрый поиск инфикса за счет немного меньшего пространства для хранения.

Кроме того, чтобы избежать поиска "Марианны" при поиске "Энн", рассмотрим:

  • Использование поиска с учетом регистра. (Fragile, может нарушиться, если ваши пользователи вводят свои имена или их поисковые запросы с неправильной заглавностью.)
  • После запроса дополнительно фильтрует результаты поиска, требуя границы слов вокруг поискового запроса (например, regex \bAnn\b).