Хайлайтинг великих текстових полів ElasticSearch

У грудні 2016 року ми з товаришем почали займатися новим проектом — системою збору-індексації-пошуку по документам. Система побудована навколо ElasticSearch (далі — ES), який ми використовуємо як основний рушій для повнотекстового пошуку.
Цінними даними, набутими в ході роботи над проектом ми б хотіли поділитися з читачами в циклі статей про ES. Почнемо з основи будь-якого пошукача — підсвічування результатів пошуку (далі — хайлайтинг).
Правильна підсвічування результатів пошуку чи не найважливіший критерій ефективності пошукової системи для користувача. По-перше, видно логіка включення документа в результати пошуку, а по-друге, підсвічування блоку знайденого тексту дає можливість швидко оцінити контекст знайденого попадання.
Однією з ключових вимог до нашої пошуковій системі була можливість швидко і ефективно працювати з великими файлами (більше 100 Мб). У статті ми розповімо, як домогтися високої продуктивності від ES при хайлайтинге великих полів документа.
На скріншоті нижче показано як працює підсвічування результатів пошуку в нашому проекті.
Приклад результатів пошуку хайлайтом
Перший крок або суть проблеми
Отже, ES ми використовуємо для зберігання і пошуку метаданих і распарсенном вміст файлів. Приклад документа, який ми зберігаємо в ES:
{
sha256: "1a4ad2c5469090928a318a4d9e4f3b21cf1451c7fdc602480e48678282ced02c",
meta: [
{
id: "21264f64460498d2d3a7ab4e1d8550e4b58c0469744005cd226d431d7a5828d0",
short_name: "quarter.pdf",
full_name: "//winserver/store/reports/quarter.pdf",
source_id: "crReports",
extension: ".pdf",
created_datetime: "2017-01-14 14:49:36.788",
updated_datetime: "2017-01-14 14:49:37.140",
extra: [],
indexed_datetime: "2017-01-16 18:32:03.712"
}
],
content: {
size: 112387192, /* Файл більше 100 Mb */
indexed_datetime: "2017-01-16 18:32:33.321",
author: "John Smith",
processed_datetime: "2017-01-16 18:32:33.321",
length: "",
language: "",
state: "processed",
title: "Quarter Report (Q4Y2016)",
type: "application/pdf",
text: ".... дуже багато тексту тут ...."
}
}

Як ви вже здогадалися, це распарсеный контент pdf файлу з фінансовим звітом розміром трохи більше 100 Мб. Поле
content.text
я навмисне вкоротив, очевидно, що його довжина приблизно дорівнює тим самим 100 Мб.
Проведемо простий експеримент: візьмемо 1000 таких документів і проиндексируем їх ES'ом не використовуючи жодних спеціальних налаштувань індексу або самого ES'а. Подивимося наскільки швидко буде працювати пошук і хайлайт по цим документам.
Результати:
  • Пошук
    match_phrase
    в полі
    content.text
    : від 5 до 30 секунд.
  • Формування хайлайта для поля
    content.text
    для кожного з документів: більше 10 секунд.
Така продуктивність нікуди не годиться. Користувач очікує побачити результати миттєво (< 200 мс), а не через десятки секунд. Давайте розберемося як вирішити проблему повільного формування хайлайта. Проблему швидкого пошуку по великих файлів розглянемо в наступній статті циклу.
Вибираємо алгоритм хайлайтинга
ES є можливість використовувати три види хайлайтеров. См. офіційний мануал.
Для тих кому ліньки читати, на пальцях:
  • Plain — варіант за замовчуванням, самий повільний, але самий якісний (за словами ES, майже на 100% відображає алгоритм пошуку Lucene, і це правда), для формування хайлайта вивантажує весь документ в пам'ять і повторно аналізує його.
  • Postings — швидкий хайлайтер, б'є поле на пропозиції і витягує для хайлайта вже не весь документ, а де знайдено пропозиції токен, ранжуючи їх за алгоритмом BM25. Потребує збагачення індексу позиціями цих пропозицій.
  • Fast Vector Highlighting (FVH) — позиціонується як самий швидкий хайлайтер, особливо для великих документів. Потребує збагачення індексу даними про положення всіх токенів у вихідному документі, завдяки цьому формує хайлайт майже за константна час, незалежно від розміру документа.
Як описано вище, за замовчуванням ES використовується Plain хайлайтер. Таким чином кожен раз для формування хайлайтов ES вивантажує в пам'ять всі 100 мегабайт тексту і відповідає на запит дуже і дуже повільно. Ми відмовилися від Plain консилера і вирішили протестувати Postings і FVH. У підсумку наш вибір припав на FVH з кількох причин:
  • Документ розміром до 100 Мб FVH в середньому хайлайтит близько 10-20 мс, Postings на це витрачає близько секунди
  • Postings не завжди коректно розбиває текст на речення, тому розмір отриманого хайлайта досить часто скаче (може повернути 50 слів, а може і 300). З FVH такої проблеми не було помічено. Він повертає задане число квитків в обидві сторони від потрапляння
  • Postings хайлайтит токени незалежно від їх положення, тому підсвічування фраз в цьому випадку працює некоректно. Наприклад
    simple_string_query
    "іванов іван"~5 захайлайтит не тільки випадки коли два токена "іванов" і "іван" будуть на відстані не більше 5 токенів один від одного, але і всі інші токени "іванов" або "іван" в заданому полі документа, як ніби це був просто
    bool
    запит
    match
    "іванов" і "іван"
Підводні камені Fast Vector Highlighter
У процесі роботи з FVH ми помітили таку проблему: пошуковий запит
match_phrase
"іванов іван" знаходить входження "іванов іван" і "іван іванов", але FVH підсвічує тільки попадання в порядку зазначеному в запиті. Цей нюанс не згадується ні в одному мануалі по ES, на нашу думку, ця помилка виникає в результаті того, що FVH враховує положення токенів
match_phrase
запиту. Проблему ми вирішили обхідним шляхом — додаємо в запит поля
highlight_query
в якому перебираються всі можливі положення токенів у фразі. Це єдиний спосіб, який дозволяв отримати всі хайлайты при цьому зберігши продуктивність на належному рівні.
Підсумок
Хайлайтить великі документи ES дійсно може, при цьому швидко. Важливо правильно налаштувати індекс, і враховувати особливості освітлення. Якщо ви вирішували схожу задачу і знайшли, як вам здається, більш елегантне рішення розкажіть про нього в коментарях.
Посилань на розроблювальний проект приводити не буду, якщо вам цікаво дізнатися про нього пишіть в ЛС.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.