Вот вы там все сидите и ничего не знаете, а мы, тем временем, пилим помаленьку мега-релиз поискового движка Sphinx за номером 3.0. Грядет ряд больших переделок. Часть из них, как полагается, ещё даже как следует не начата. Однако большая часть уже скорее готова, чем нет. А отдельно взятые изменения даже протекли в публичную ветку 2.3. Так что, пожалуй, настало время вкратце начинать рассказывать, чего ожидать в светлом будущем: надеюсь, не столь отдалённом. Кому интересно почитать, все под кат; кому послушать, приходите на meetup в эту субботу. Если совсем вкратце, то: прощай, концепция дополняющего основную базу движка; привет, хранилище документов, тотальный RT, репликация, REST и ряд других известных ключевых слов.

Начнем собственно с главного, короткий список запланированных больших изменений:
  • новый формат FT индекса: быстрее индексация, быстрее поиск, меньше размер;
  • новый формат атрибутов: прощайте, все дурацкие исторические ограничения;
  • полный переход на треды: прощай, директива workers, привет, thread pool;
  • полный переход на RT индексы: причем indexer остается, а вот директива type не очень;
  • онлайн репликация RT индексов: постепенно заменяем адский ручной кластер на автоматический;
  • хранилка оригиналов документов: прощай, концепция auxiliary index, привет, мир, теперь мы тоже как бы база;
  • нативные индексы атрибутов: эмуляция ключевиками кое-как работает, а вот индексами возможно пользоваться;
  • REST интерфейс: API для ботов, SQL для себя, REST для людей.


Два больших внутренних изменения это, конечно, со всех сторон (и в полнотекстовой и атрибутивной части) новый формат индекса, плюс форсированный переход на строго тредовую модель работы и строго RT индексы. Отчего и зачем это все?

Старый формат FT индекса концептуально тянется, страшно подумать, аж с 2001 года. Не, в нём, разумеется, регулярно делались некие изменения и оптимизации, поэтому старичок ещё бодрячком. Однако радикальных, концептуальных изменений не было, натурально, вот прямо с 2001 года. Как хранили пачку varint закодированных дельт внешних docid, так и храним. Причем, будучи довольно низкоуровневым кирпичиком, формат индекса влияет не только лишь на собственно хранение данных, а затрагивает и ещё ряд штук во внутренней архитектуре, которые потом протекают и наружу: требование обязательно предоставлять внешний DocID, головные боли с дубликатами документов, ряд странных моментов в производительности, вот это вот всё.

Сегодня мы можем сделать и получше.

В новом формате нету «магического» внешнего уникального атрибута DocID, внутренняя нумерация документов отвязана от внешней. Одно это изменение делает возможным кучу штук: внезапно, в индекс можно заливать дубликаты ID, или вообще не требовать никакого числового ID; внезапно, при необходимости для подмножества документов индекса можно строить компакетные битмаски, а не здоровенные списки ID; внезапно, собственно данные полнотекстового индекса возможно куда эффективнее сжимать всякими групповыми кодеками типа PFD, Group Varint и прочая; внезапно, при индексации не нужен занудный этап сортировки, индекс можно строить практически инкрементально; и так далее. Индекс становится до 1.5 раз меньше, строится в 2-3 раза быстрее и, теоретически, искать по нему тоже можно до 2-3 раз быстрее, по меньшей мере, на отдельных запросах. Профит со всех сторон.

Последнее провоцирует следующую мелкую революцию. Раз новый инкрементальный алгоритм индексации (который, грубо говоря, «дописывает» по 1 записи к существующему недоиндексу в памяти) без затей оказался в 2-3 раза быстрее существующей сейчас пакетной индексации дисковых индексов, то — зачем вообще различать дисковые индексы и RT индексы? Отлично, долой дисковые индексы, долой директиву type. Раз теперь мы можем все индексы сделать RT, причем без потери производительности, скорее даже с ускорением, значит, надо это сделать. (Внутри при этом все равно остаются disk/RAM based варианты реализации отдельных сегментов индекса, конечно. Диск и память таки отличаются по ТТХ и не помнить об этом нельзя. Однако это уже вчистую головная боль «как сделать эффективно» для разработчиков, а заметных снаружи функциональных отличий для пользователей быть не должно.)

Что интересно, при этом утилита indexer, в принципе, никуда не пропадает. ETL инструмент для выгрузки данных из базы и загрузки их в поиск все равно иметь полезно. Однако раньше оно строило дисковый индекс, а теперь будет строить RT индекс (либо для прямой загрузки в демона, либо для «приклеивания» свежепроиндексированного пакета данных к существующему индексу, это уже не суть важно).

Раз уж всё равно сильно меняется формат полнотекстовой части, то заодно надо сменить и формат хранения атрибутов, гулять так гулять (ломать совместимость, так ломать)!!! Теперь все колонки переменной длины (строки, MVA, JSON и любые другие хитрые типа, если вдруг в будущем таковые будут таки добавляться) для одного документа складируются в один большой блоб, и указатель на этот блоб хранится тоже один. (А раньше на каждый тип был отдельный файл, а колонку отдельный указатель, охх.) При этом заодно изжита глупая ошибка молодости «4 GB should be enough for everybody», плюс все можно унифицированно обновлять, удалять и так далее. Итого атрибуты фиксированной длины хранятся как и раньше (вот только за счет перехода на внутренние номера доступ к ним много быстрее), атрибуты переменной длины жрут несколько меньше памяти (8 байт на все сразу, а не 4 байта на каждый), плюс теперь никак не ограничены по размеру. Плюс прочие мелкие приятные улучшения: например, формат теперь поддерживает честный NULL. Или вот внутри JSON данных теперь делается компрессия ключей.

Переход на RT в свою очередь означает, что fork/prefork становится дальше поддерживать не просто тяжело, а невозможно. Впрочем, здесь в кои веки есть решение «и быстро и хорошо», без этих вот проклятых компромиссов: thread pool (уже доступный в 2.3) работает максимально бодро с точки зрения скорости поисков (см. быстро), принципиальная модель параллельной обработки остается как бы одна, многопоточная, а не многопроцессная (см. хорошо). Если бы ещё и креши умудрялись затрагивать только один тред, было бы вообще идеально, но идеально в жизни не бывает. Поэтому для облегчения болей от креша теперь подавляющая часть нужных данных на старте таки mmap()ится, а не копируется, за счет чего запуск (и перезапуск) даже с большими индексами стал довольно резв.

Вдобавок к тредам из-за форсирования RT становится совсем-совсем нужна репликация. Раз декларируем отказ от дисковых индексов, которые хоть как-то можно было копировать в виде файлов туда-сюда, значит, надо хоть какие-то инструменты для RT. Можно, конечно, делать горячий backup/restore, но это скучно. Онлайн репликацию RT индексов сделать куда интереснее. Что же, делаем. 1 мастер, N динамических реплик, автоматический переброс начального снапшота, репликация влетающих изменений, перевыбора мастера, все эти дела. Следующим шагом всякие инструменты для построения и менеджмента кластера, но сначала пусть репликация совсем хорошо заживет.

Реплицировать «просто полнотекстовые индексы» как-то мелко, плюс давать сохранить оригиналы документов ведь регулярно просят, плюс для дополнительного ускорения сниппетов необходимо уметь сохранять блоб со всяким странным фаршем, плюс отвязанный от docid формат индекса позволяет всякое ловко реализовать. Что же, делаем ещё и docstore, те. дисковое хранилище не только атрибутов, но и полей индексируемых документов, а также всякой привязанной метаинформации (пока что это только document level индексы для сниппетов). Маленький шажок для кода, большой для функционала: теперь в Сфинкс можно складывать не только лишь полнотекстовый индекс, а таки полностью использовать как базу. Странноватую, но базу.

В базе неплохо бы иметь индексы не только по ключевым словам, поэтому заодно надо озаботится индексами по атрибутам. Ну, это чтобы WHERE MATCH('the who') AND author=1234 исполнялось «от индекса», чтобы WHERE MATCH('biggest rarity') AND gender='m' исполнялось таки «от поиска», но и то и другое автоматически исполнялось оптимально, а не так, что в вызывающем PHP скрипте надо реализовать аналог SQL оптимизатора и генератор запросов типа WHERE MATCH('the who _author1234'). Тупо проэмулировать атрибуты облачком ключевых слов, как вроде (вроде) до сих пор принято известно где, тоже, конечно, можно, но если уже делать, так по большому!!!

И, наконец, SQL это немодно, плюс не отовсюду удобно вызывать, поэтому надо добавлять HTTP/REST доступ. Совсем базовая начальная реализация уже есть в 2.3, оттуда будем расширять и углублять. Ничего интересного, даже скучно.

Вот со всем этим Sphinx 3.0 и попытается взлететь.

Ряд описанного, конечно, всё ещё в стадии разработки и в начальные альфы может и не войти. Однако общий план именно такой, плюс, скажем так, больше половины этого плана уже таки сделано. Работы осталось изрядно, но поворачивать назад уже поздно!!!

Понятно, что по каждому отдельному большому пункту можно писать отдельную изрядную статью с кучей технических деталей, но надо с чего-то начинать. Вот, я попытался сделать небольшой обзор грядущих изменений. Чуть подробнее все то же самое буду рассказывать через 3 дня, в эту субботу на встрече Sphinx-оводов (понятное дело, Москва), у кого сразу возник миллион уточняющих вопросов и нету никакой возможности писать их все в комментарии, заходите на огонёк, попробую ответить. По мере возможностей буду писать сюда (и-или в блог на сайте) ещё статей про грядущие мегафичи.

В общем и целом, грядет Sphinx 3.0, грядет куча переделок, думаю, будет интересно.

Ведь не может же в мире существовать ровно ОДНА библиотека для полнотекстового поиска, да и та на богомерзкой Java?!!! :-)

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


  1. azer
    12.05.2015 21:30
    +5

    Замечательный у вас движок.

    Но, тот, кому нужны были эти ваши «мегафичи», уже поставил ElasticSearch.

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

    Сегодня внедрять их смысла нет. Разве что для импортозамещения. Но вы мало похожи на импортозаместителей.


    1. Envek
      12.05.2015 21:45
      +10

      ElasticSearch весьма велик (Java всё таки), а нынешний Sphinx кушает всего несколько мегабайт памяти (если делать поиск для небольшого сайта).
      Правда на поприще «дёшево, сердито и чтоб не париться» на пятки наступает PostgreSQL — у них уже можно делать полнотекстовый поиск с некоторыми обязательными для такого поиска плюшками (типа стоп-слов) прям силами самой РСУБД.


      1. gonzazoid
        12.05.2015 22:06
        +1

        теги читаю, sql за модой не гонится, а что бы слон на пятки не наступал — не убегайте от его, а сделайте интеграцию из коробки. И удачи в реализации планов!


      1. azer
        13.05.2015 01:14
        -1

        ElasticSearch действительно велик. Ещё он неудобен своими настройками и странноватым языком запросов.
        Но он имеет то, чего нет у сфинкса и это перевешивает его недостатки.


        1. pavlick
          13.05.2015 03:13
          +4

          кажется, что как раз своими настройками (вообще подо все) он очень удобен.


        1. ComodoHacker
          13.05.2015 18:48

          В Эластике есть русская морфология из коробки?


          1. grossws
            13.05.2015 20:40

            Стемминг есть, он в solr с незапамятных времен есть, а elastic конкурирует, в основном, с ним. Плюс можно использовать russianmorphology на базе, как я понимаю, AOT'а.


      1. Aco
        13.05.2015 12:09
        -1

        не только велИк, но и, судя по нашим тестам, проигрывает в скорости индексации и поиска Сфинксу.


    1. prn
      12.05.2015 22:17
      +3

      elastic ок, но в нашем случае результаты сравнения его со sphinx такие (не в пользу elastic):

      • средняя скорость поиска 1:5 (относительная разница)
      • размер индексов 1:4 — это после того, как убрали хранение доков в elasticsearch
      • скорость индексации 1:8


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


      1. pavlick
        13.05.2015 03:14

        а если размер индексов несколько терабайт?


        1. prn
          13.05.2015 11:53

          а какие с этим могут проблемы в sphinx?
          он прекрасно будет работать, если места на диске или кластере хватает.
          На HL++ Вячеслав Крюков еще в 13-ом году делал доклад на эту тему www.highload.ru/2013/abstracts/1229.html


          1. pavlick
            13.05.2015 12:27

            Не знаю, потому и спрашиваю. Очень давно не работал со сфинксом. Надо посмотреть


    1. sebres
      13.05.2015 13:18
      +1

      ElasticSearch? Вы серьезно? Нет я понимаю сравнивать еще Solr со Sphinx, но эластик просто по всем основным параметрам, типа скорость, гибкость настройки и т.д. просто рядом не стоял… Про масштабируемость я вообще промолчу.


      1. Acvilon
        13.05.2015 17:48

        А можно поподробнее? У какой системы проблемы с масштабируемостью?


        1. sebres
          15.05.2015 12:35

          У всех, но у эластика — гигантские… Пересоздавать полутерабайтный индекс (который помер) — то еще удовольствие.


      1. azer
        13.05.2015 21:41
        +1

        Вы правы насчет гибкости и скорости sphinx. Но топик вообще-то не об этом. Топик этот — о запоздалых заявках на «мегафичи».
        Которые у Elastic и Solr есть уже давно.


    1. mikhailov
      17.05.2015 12:32

      Elastic очень хорош, но Sphinx был лучший несколько лет назад. Время догнать и обогнать.


  1. t1gor
    12.05.2015 22:52

    Спасибо за статью, будем ждать релиза. Есть небольшой вопрос: при переходе на новую версию, я так понимаю, что при миграции придется заморочиться с конфитурацией (читай все переделать)?


    1. shodan Автор
      13.05.2015 01:43
      -1

      Миграцию как раз конфигурации мы должны суметь сделать сделать довольно легкой. Там основная часть про sources/indexes по существу должна переехать в отдельный indexer.conf практически без изменений, а остального очень мало, это все легко переделать вручную, либо автоматом (условный скрипт upgrade.py) сконвертировать разово.

      Меня больше беспокоит миграция больших индексов, тк. конверсия в новый формат а) будет возможна только при соблюдении ряда условий, dict=keywords + docinfo=extern + еще ряд более эзотерических штук (отсутствие hitless итп), б) даже в случаях, где возможна, может оказаться слишком медленной (ну те. может оказаться проще переналить данные заново, чем сконвертировать существующий индекс). Впрочем, так или иначе оно все решаемо.

      Цена прогресса, шо поделать. Много лет держали бинарную совместимость довольно неплохо, пора наконец разок сломать!!!


      1. t1gor
        13.05.2015 10:24

        Спасибо за объяснения.

        dict=keywords + docinfo=extern
        ну тут все понятно, а
        отсутствие hitless итп
        — это что? Где можно почитать?


        1. shodan Автор
          13.05.2015 11:37

          — это что? Где можно почитать?

          Это как пример эзотерической штуки, из-за которой сконвертировать индекс окажется невозможно. Беспозиционный (частично или полностью) индекс. sphinxsearch.com/docs/current.html#conf-hitless-words


  1. 4umak
    12.05.2015 23:57
    +1

    А когда грядёт то?:)

    Хочется http-управления, как в эластике, чтобы можно было налету создавать отдельные индексы, наполнять их данными и настраивать параметры поиска.


    1. shodan Автор
      13.05.2015 01:56
      +2

      Грядет в этом году. Увы, точнее пока не могу оценить.

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

      Менеджмент индексов на лету (не только через HTTP) тоже планируется, да. Возможно, не в первой же альфе 3.0, но планируется.



  1. Demetros
    13.05.2015 07:28
    +1

    Удачи, радует, что и такие крутые вещи делаются нашими людьми )
    У меня сфинкс (еще какой-то лохматой версии) работает месяцами, рестартуется только при обновлениях на сервере. И при этом на сайте быстрый и внятный поиск.


  1. sebres
    13.05.2015 13:21
    +1

    хранилка оригиналов документов
    я надеюсь это отключаемо? А то если «как бы база» не нужна, чтобы то есть не хранить дважды…


    1. shodan Автор
      13.05.2015 13:48
      +2

      Да, отключаемо (или не включаемо, пока не решил, какой лучше дефолт).


      1. catanfa
        13.05.2015 23:33

        если будет «невключаемо», то невозможно будет включить попробовать)


  1. seregagl
    13.05.2015 14:21

    Андрей, а можно пару слов об HTTP/REST доступе в 2.3. В документации я такого нигде не встречал, о какой базовой реализации идет речь?


    1. shodan Автор
      13.05.2015 15:30
      +1

      Оно доступно в SVN транке. Пока неотдокументировано примерно никак с одной стороны и практически нету никаких endpoints и опций к ним с другой, но таки уже:

      searchd
      {
          workers = threadpool
          listen = localhost:9380:http
      }
      
      http://localhost:9380/sql/?query=select%20*%20from%20rt
      
      {
          "attrs": ["id","gid","gid2","date_added","title","content"],
          "matches": [
              [1,1,[5],1428361133,"test one 24 mois","this is my test document number one"],
          ...
      }
      


  1. tattoor
    27.05.2015 17:32

    Есть у кого-нибудь видео встречи?