Как, используя Lucene, построить
высоконагруженную систему поиска
разнородных данных
Одноклассники в цифрах
• Что у нас есть:
  – 100 млн пользователей;
  – 3.3 млн групп;
  – .....
• 4.1 млн пользователей онлайн;
• В секунду:
  – 250. тыс. страниц, 50мс, 70Гбит/с;
  – 6 тыс. сообщений и комментариев;
  – 1.5 тыс. поисковых запросов.



                                         1
Зачем нам понадобились свои поисковые
системы?

• Пользователь не всегда знает, как именно
  регистрировался искомый друг
• На сайте были огромные каталоги групп и
  сообществ
• Планировались новые сервисы, которым
  понадобится поиск
• Как правило, человек ищет то, что уже есть у
  кого-то из его друзей

                                                 2
Почему Lucene?

• Поиск по MS SQL базе был крайне медленным
• На Java написано 99% нашего кода, поэтому
  Sphinx даже не смотрели
• Apachе Lucene/Solr поддерживаются большим
  сообществом и хорошо себя зарекомендовали
• Уже был опыт использования Solr
• Быстрый поиск других поисковых
  Java-проектов результатов не дал

                                          3
Как устроен Lucene?
The bright                                            Term        DocId   DocId   Values
blue                                                  blue        1,2     1       333, Author A




                                                                                                  Index Reader & Searcher & Query parser
butterfly                                             bright      1,2     2       777, Author C
hangs on


                 Tokenizers & Filters & IndexWriter
                                                      butterfly   1
the breeze
                                                      breeze      1
                                                      hangs       1
Under blue
sky, in bright                                        need        2
sunlight,                                             search      2
one need                                              sky         2
not search
around


                                                      Term        DocId   DocId   Values
It’s best to                                          best        1       1       555, Author C
forget the                                            forget      1
great sky
                                                      great       1
and to retire
from every                                            retire      1
wind                                                  sky         1
                                                      wind        1


                                                                                                                                           4
Требования к системе индексов

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


                                          5
Что нас не устроило в Solr

• Solr:
   –   сервер использует только один процессор
   –   репликация индексов на bash-скриптах
   –   http - это дорого и медленно
   –   сложно модифицировать
• Но Lucene нас устраивает, поэтому пишем
  свой сервер



                                                 6
Архитектура

                              Presentation
         Query




                                                     Event
                 Result




                                                             Result
   Search processing system        Read          Services




                                                                      Update/Notify
         Query




                                              Read
                 Results




                 Index          Replication   Indexer + DB



                                                                                      7
Требования к поисковой системе

• Отказоустойчивость
• Использование социального графа
• Эффективность
• Простое изменение и расширение
  функциональности
• Сбор статистики по пользователям
• Высокая пропускная способность


                                     8
Как работает поисковая система


    Get session for Schema


      Schedule queries


       Execute queries
                waitAll ()
                waitFor (queries complete)
                waitAtLeast (result items)


        Reduce results


         Load results




                                             9
Проблемы: работа с индексом
• Lucene активно читает файлы во время поиска
• Пробовали:
  –   Диск с FSDirectory и NIODirectory
  –   RamDrive с FSDirectory и NIODirectory
  –   Lucene RamDirectory
  –   Собственный UnsafeDirectory
• Победил:
  – HeapDirectоry файлы как byte[] в хипе



                                              10
Проблемы: ThreadLocal кэши
• Долгий GC из-за уймы мелких объектов в хипе
• Причины:
  – Lucene использует ThreadLocal кэши для
    некоторых объектов
  – Jboss Remoting на каждое соединение содает
    поток, а их тысячи
• Первое решение:
  – Пул для выполнения запросов
• Второе решение:
  – Делая другую оптимизацию, убрали эти кэши

                                                 11
Проблемы: медленные хранимые поля
• Медленная работа с хранимыми полями
• Причина:
  – При считывании хранимого поля создается много
    мусора и производятся ненужные операции
• Решение:
  – Считывать значение в нужный тип сразу из byte[]
• Результат:
  – На порядок быстрее стали операции с хранимыми
    полями
  – Время GC упало в 2 раза

                                                      12
Распознавание полей
• Поиск пользователей идет по следующим полям:
      имя и фамилия, город, страна, интервал возростов
• Друга можно искать, вводя известные данные:
  «илья широков 30»
  «илья широков москва»
  «илья широков 25-30 россия»



                                             Query Line
    User       Term       Term     Search
   Index      Collector   Dict.    System
                                             Fields Query




                                                            13
Поиск по возрасту
• Стандартные решения:
  – Добавление всех подходящих терминов
  – Префиксные термины для снижения количества
    терминов в запросе
  – Запрос к FieldCache
  – Фильтр результатов
• Наше решение:
  – Возраст хранится ввиде даты: yyyymmdd
  – Запрос по текстовым полям оборачивается в
    фильтрующий запрос, который проверяет отбраные
    документы по хранимому полю

                                                     14
Поиск музыки
• В базе есть:
    – артисты; альбомы; композиции
    – не сортированые музыкальные композиции
• Три точности совпадения:
    точное; все слова из запроса; некоторые слова из запроса
•   Поиск всегда идет по всем видам документов
•   От точности совпадения зависит поведение UI
•   На место в выдаче влияет рейтинг документа
•   С индекса собираются всевозможные топы


                                                           15
Индексация музыки
• Все храним в одном индексе
• У каждого документа:
  –   в id зашит его тип (артист; альбом; композиция; файл)
  –   тип как отдельное поле
  –   рейтинг как параметр индексации
  –   рейтинг как хранимое поле
• Текстовые поля:
  – по отдельности
  – необходимые комбинации
  – 2 представления текста: оригинал + фонетика

                                                              16
Поиск музыки
• Пробовали:
  – Отдельный запросы для каждого типа
  – Повторные запросы с меньшей точностью
  – Настройка оценщика веса для результата
• Решение:
  – Запрос состоит из комбинаций: точность + поле данных
  – Для каждой комбинации есть интервал значений весов
  – Вес из подзапроса нормализуется в интервал
    комбинации
  – Если документ отвечает запросу, сразу вычисляем его
    тип и добавляем в соответствующий коллектор

                                                       17
Поисковые сервера

                                 Группы
  Пользователи                 Сообщества
   8 серверов                   2 сервера
    7 000 МБ                     600 МБ
      20 мс        Поисковая       3 мс
    1100 з/c                     2200 з/c
                    система
                 5 серверов
                 10 000 МБ
                    90 мс
    Музыка        1500 з/c       Видео
    4 сервера                  6 серверов
     2700 МБ                     400 МБ
       50 мс                       7 мс
      200 з/c                     30 з/c




                                            18
Спасибо!

Алексей Шевчук
odnoklassniki.ru/aleksey.shevchuk
Разработчик поисковых систем
Одноклассники




         hr@odnoklassniki.ru

Как, используя Lucene, построить высоконагруженную систему поиска разнородных данных

  • 1.
    Как, используя Lucene,построить высоконагруженную систему поиска разнородных данных
  • 2.
    Одноклассники в цифрах •Что у нас есть: – 100 млн пользователей; – 3.3 млн групп; – ..... • 4.1 млн пользователей онлайн; • В секунду: – 250. тыс. страниц, 50мс, 70Гбит/с; – 6 тыс. сообщений и комментариев; – 1.5 тыс. поисковых запросов. 1
  • 3.
    Зачем нам понадобилисьсвои поисковые системы? • Пользователь не всегда знает, как именно регистрировался искомый друг • На сайте были огромные каталоги групп и сообществ • Планировались новые сервисы, которым понадобится поиск • Как правило, человек ищет то, что уже есть у кого-то из его друзей 2
  • 4.
    Почему Lucene? • Поискпо MS SQL базе был крайне медленным • На Java написано 99% нашего кода, поэтому Sphinx даже не смотрели • Apachе Lucene/Solr поддерживаются большим сообществом и хорошо себя зарекомендовали • Уже был опыт использования Solr • Быстрый поиск других поисковых Java-проектов результатов не дал 3
  • 5.
    Как устроен Lucene? Thebright Term DocId DocId Values blue blue 1,2 1 333, Author A Index Reader & Searcher & Query parser butterfly bright 1,2 2 777, Author C hangs on Tokenizers & Filters & IndexWriter butterfly 1 the breeze breeze 1 hangs 1 Under blue sky, in bright need 2 sunlight, search 2 one need sky 2 not search around Term DocId DocId Values It’s best to best 1 1 555, Author C forget the forget 1 great sky great 1 and to retire from every retire 1 wind sky 1 wind 1 4
  • 6.
    Требования к системеиндексов • Отказоустойчивость и масштабируемость • Высокая производительность поисковых серверов • Гибкое индексирование • Возможность сбора дополнительной информации перед индексацией • Возможность анализа готового индекса 5
  • 7.
    Что нас неустроило в Solr • Solr: – сервер использует только один процессор – репликация индексов на bash-скриптах – http - это дорого и медленно – сложно модифицировать • Но Lucene нас устраивает, поэтому пишем свой сервер 6
  • 8.
    Архитектура Presentation Query Event Result Result Search processing system Read Services Update/Notify Query Read Results Index Replication Indexer + DB 7
  • 9.
    Требования к поисковойсистеме • Отказоустойчивость • Использование социального графа • Эффективность • Простое изменение и расширение функциональности • Сбор статистики по пользователям • Высокая пропускная способность 8
  • 10.
    Как работает поисковаясистема Get session for Schema Schedule queries Execute queries waitAll () waitFor (queries complete) waitAtLeast (result items) Reduce results Load results 9
  • 11.
    Проблемы: работа синдексом • Lucene активно читает файлы во время поиска • Пробовали: – Диск с FSDirectory и NIODirectory – RamDrive с FSDirectory и NIODirectory – Lucene RamDirectory – Собственный UnsafeDirectory • Победил: – HeapDirectоry файлы как byte[] в хипе 10
  • 12.
    Проблемы: ThreadLocal кэши •Долгий GC из-за уймы мелких объектов в хипе • Причины: – Lucene использует ThreadLocal кэши для некоторых объектов – Jboss Remoting на каждое соединение содает поток, а их тысячи • Первое решение: – Пул для выполнения запросов • Второе решение: – Делая другую оптимизацию, убрали эти кэши 11
  • 13.
    Проблемы: медленные хранимыеполя • Медленная работа с хранимыми полями • Причина: – При считывании хранимого поля создается много мусора и производятся ненужные операции • Решение: – Считывать значение в нужный тип сразу из byte[] • Результат: – На порядок быстрее стали операции с хранимыми полями – Время GC упало в 2 раза 12
  • 14.
    Распознавание полей • Поискпользователей идет по следующим полям: имя и фамилия, город, страна, интервал возростов • Друга можно искать, вводя известные данные: «илья широков 30» «илья широков москва» «илья широков 25-30 россия» Query Line User Term Term Search Index Collector Dict. System Fields Query 13
  • 15.
    Поиск по возрасту •Стандартные решения: – Добавление всех подходящих терминов – Префиксные термины для снижения количества терминов в запросе – Запрос к FieldCache – Фильтр результатов • Наше решение: – Возраст хранится ввиде даты: yyyymmdd – Запрос по текстовым полям оборачивается в фильтрующий запрос, который проверяет отбраные документы по хранимому полю 14
  • 16.
    Поиск музыки • Вбазе есть: – артисты; альбомы; композиции – не сортированые музыкальные композиции • Три точности совпадения: точное; все слова из запроса; некоторые слова из запроса • Поиск всегда идет по всем видам документов • От точности совпадения зависит поведение UI • На место в выдаче влияет рейтинг документа • С индекса собираются всевозможные топы 15
  • 17.
    Индексация музыки • Всехраним в одном индексе • У каждого документа: – в id зашит его тип (артист; альбом; композиция; файл) – тип как отдельное поле – рейтинг как параметр индексации – рейтинг как хранимое поле • Текстовые поля: – по отдельности – необходимые комбинации – 2 представления текста: оригинал + фонетика 16
  • 18.
    Поиск музыки • Пробовали: – Отдельный запросы для каждого типа – Повторные запросы с меньшей точностью – Настройка оценщика веса для результата • Решение: – Запрос состоит из комбинаций: точность + поле данных – Для каждой комбинации есть интервал значений весов – Вес из подзапроса нормализуется в интервал комбинации – Если документ отвечает запросу, сразу вычисляем его тип и добавляем в соответствующий коллектор 17
  • 19.
    Поисковые сервера Группы Пользователи Сообщества 8 серверов 2 сервера 7 000 МБ 600 МБ 20 мс Поисковая 3 мс 1100 з/c 2200 з/c система 5 серверов 10 000 МБ 90 мс Музыка 1500 з/c Видео 4 сервера 6 серверов 2700 МБ 400 МБ 50 мс 7 мс 200 з/c 30 з/c 18
  • 20.

Editor's Notes

  • #3 Хотелось находить, несмотря на опечатки, с учетом истории, и ранжировать не по айдишке
  • #4 НедавноSQLперестал искать по именам даже в админке
  • #5 Инвертированый индекс - это индексная структура, которая хранит не отдельные поля документов, а данные из этих полей: слова, цифры и т.д. Через такую структуру можно быстро находить документы, содержащие необходимые слова, все или часть из них.
  • #6 Эти требования были выработаны на основании нашего опыта и моделирования необходимого функционала
  • #8 Такая схема обеспечивает лучшую стабильностьи возможности оптимизации, но нет возможности сделать NRTГлавным конкурентом такой схемы является препроцессор, которые готовит данный и рассылает их на ПС. Появляется рассинхронизация, двойная работа на ПС, негде анализировать индексы.Реплицируем необходимые фаилы ввиде byte[]
  • #9 Мы знаем о пользователях гораздо больше, чем обычная поисковая система, и мы стараемся этим пользоваться. Эффективность – из-за отсутствия схем всегда собирается полный граф, может быть меньше вызовов на подготовке результатовПроблемы первой версии с бобром и лосёмЭто требования для системы которой одновременно пользуется более 70.000 человек.
  • #10 Схема описывает, какие данные из соц графа (более 30 видов) нужны для запросаСейчас 5 схем и 4 вида результатов, будет большеИндексы не храняться т.к. Проще пересобирать их при необходимости нежели пытаться апдейтить 100.000.000 индивидуальных индексовКэширование результатов было, но отказались – проще когда надо повторить запрос. Такой же опыт у твиттераМгновенный поиск запускали одновременно с гуглом
  • #11 ВLinux очень эффективное кэширование, но тут оно не сработалоВыделеные сервера для выполнения запросов позволили выжать максимум из них
  • #13 Данные проблемы следствие универсальности Lucene, но нам нужна эффективностьПотребовалось переписать несколько ключевых классовСнизило время GCв 2 раза для обычных поисков и в разы ускорило поиск музыки, схоже с тем что будет в 4ой Lucene
  • #14 Поиск должен быть не только быстрым но и удобнымБыли моменты когда бал только детальный и только строка – оба варианта вызывали недовольствоСборка словаря встроена как конфигурируемая фича и делается автоматическиТак же через отдельный словарик сделаный с SQL данных находим странуНераспознанные слова считаются именамиПроблемы с «Иван Ростов»Сделать как то иначе мешает черезчур большой размер словаряВ словарь попадают только слова с определенной частотой
  • #15 RangeQuery даже не пробовалиFieldCacheработающий в LinkedIn не подошел из-за того что у нас боьшие партицииМеханизм фильтрации Lucene тоже не работает для таких больших индексов
  • #16 Как Luceneотбирает документы:Документ должен отвечать булевой логике запросаТочность соответствия вычисляется с использованием Векторной модели (vector space model) – получается вес результата
  • #18 Для каждого подзапроса есть база, размер интервала и ожидаемое максимальное значение.Музыка работает так медленно т.к. требования сильно изменились к моменту запуска. При новых требованиях хранение 4 видов документов в одном индексе создает большие проблемы.
  • #19 Микропоиски:ДрузейИгры и приложенияПодарочкиПомощьГородаCPU 15-30%С поиска сообществ случайно сняли более 3000 в секунду без нагрузки на серверЧто дал переход на Lucene для поиска пользователей:Вместо установки еще минимум 16 серверов с дорогущим MS SQL мы поставили 13 серверов с Linux и Java (могли обойтись 8ю)Время поиска упало до десятков милисекундПолучили обработку опечаток, выдачу с учетом точности совпадения, поиск по девечий фамилии и старым именам и городамЗатраты : 5 месяцев одного программиста, без знания как устроен портал и поисковые системыМикропоиски работают на своем движке, но скорее всего скоро смигряем на Lucene