Асинхронные запросы для увеличения скорости поиска


#1

ДАНО: Есть индекс с некоторым количеством документов. Необходимо пройтись по огромному списку (70 млн строк) данных из CSV файла и найти совпадения с документами в индексе. Есть скрипт (Python или PHP), внутри которого реализован поиск по индексу. На текущем железе, с текущей сложностью запроса можно выжать не более 60 запросов в секунду. Оптимизировалось пожалуй всё что приходило в голову.

ВОПРОС: возможно ли реализовать асинхронный поиск по индексу? Т.е. пока происходит поиск по первому запросу сделать ещё, допустим 99, а по мере поступления ответов от индекса, добавлять запросы таким образом чтобы "в работе" были всегда те самые 100 запросов? Имеет ли смысл такая схема?

Если есть опыт увеличения скорости поиска, буду благодарен любым ответам!


(Igor Motov) #2

Некоторым - это сколько?

Что значит совпадение?

А можно взглянуть на результат вашей оптимизации, может что-нибудь еще в голову прийдет?

Конечно, elasticsearch был создан для многопоточных запросов

В большинстве случаев, при увеличении количества одновременных запросов, все упрется либо в диск, либо в ЦПУ. Поэтому elasticsearch ищет на весьма ограниченном количестве потоков, число которых зависит от количества процессоров на машине (int((# of available_processors * 3) / 2) + 1).

Опыт есть, только информации вы дали слишком мало чтобы конкретно помочь. Не понятно, какой версией вы пользуетесь, сколько одновременных запросов вы в данный момент запускаете, как выглядит ваш запрос, схема индекса, где основная нагрузка - на диске, ЦПУ, сеть, сам скрипт и т.д.


#3

Igor_Motov Огромное вам спасибо за внимание к моей проблеме.

Около 3 млн.

В CSV файле есть строки, которые возможно будут совпадать с определёнными полями документа. Используется как Fuzzy, так и Match типы поиска в одном запросе.

Конечно можно, правда надо будет много описать (Вспомнить всё!). Из основного, на практике стало понятно, что делать много запросов, смотреть что получилось и принимать решение о дополнительных запросах дороже, чем включить всё в один запрос и забрать лучший по score ответ. Была идея запихнуть всё в одно поле - чем меньше полей тем быстрее поиск, но надо проверить на точное совпадение, а при добавлении всё в одно поле это не возможно. На точное совпадение нужно проверять потому что Match поиск возвращает приоритетно поля где терм возможно встречается более одного раза, не смотря на то что в исходной строке он встречается всего один раз. В этом случае совпадение будет не верным. Проблема ещё в том, что железо ограничено и сделать быстрый поиск надо на том что есть.

Сервер Debian | Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz 4 ядра | 16 Gb RAM | Java: -Xms2g -Xmx2g
Эластик 6.2.4
PHP 7.2 + Elasticsearch-php
Python 3.7 + Elasticsearch-py
Увеличение памяти для Java (до половины RAM) существенно на скорость не повлияло.

Index mapping

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

Скрипт на PHP работает быстрее Python, т.е. работаем с PHP.

Основная задача: есть много csv файлов, которые содержат десятки миллионов строк, в строке есть три интересующих нас поля: трек, исполнитель, автор. Допустим сейчас этап, при котором надо пройтись по 70 млн строк. При текущей конфигурации, поиск круглосуточно, при 60 (в среднем) запросах в секунду, занимает 16 суток. PHP работает синхронно - сделали один запрос - ждём ответ. Есть библиотеки для асинхронной работы PHP, однако как при этом работает Elasticsearch-php библиотека - мне не понятно - будет ли она блокирующей и вообще. Поэтому была попытка протестировать асинхронные запросы на Python где есть asyncio и elasticsearch-py-async, однако не имея хорошего опыта работы с питоном вообще и с асинхронным в частности, на этом я и остановился в своём рисёрче. Основные этапы работы скрипта:

  1. Скрипт читает файлы построчно или грузит в память - на скорость принципиально не влияет.
  2. Далее есть манипуляции с очисткой строк и пр., так же не влияет принципиально на скорость.
  3. Поиск по индексу, занимает основное время работы скрипта, поиск происходит по 11 полям. Строки могут совпадать, для этого используется Fuzzy с нечёткостью в 1 символ (больше 1 будет дико тормозить), в том же запросе используется ещё полнотекстовый Match поиск. Строки в индексе хранятся как в кириллице, так и в транслитерации, т.к. строки для поиска могут быть и в транслите и в кириллице и заранее это не известно. Все виды поиска в одном запросе, плюс есть Boost на поля где совпадение наиболее важно. Результат с лучшим совпадением соответственно получает наибольший score.
  4. Результат пишется в итоговый csv файл, что тоже принципиально не влияет на скорость, пробовали не писать на диск а создавать файл в оперативке, выигрыш - копейки.

Буду премного благодарен любым замечаниям и идеям.


(Igor Motov) #4

Может, тогда надо индексировать 17млн CSV файл и искать в нем эти 3 запроса

Это могло ухудшить ситуацию, так как кэшу файловой системе места стало меньше.

Вот что я вижу из предоставленной информации.

  • Если все это работает на одном сервере, то лучше увеличить количество одновременных запросов и уменьшить количество шард до 1.

  • то, что находится в must лучше всего переставить в filter

  • хотелось бы посмотреть на вывод hot_threads пока у вас запрос работает, но я думаю, что проблема может в первичной обработке fuzzy. Было бы разумно проиндексировать их как одно поле (можно не менять структуру документа, а просто выключить индексацию по ним по отдельности и скопировать их в одно поле через copy_to).

  • кстати про fuzzy, какую проблему вы пытаетесь тут решить? Может вам лучше фонетически этих авторов проиндексировать? Я думаю, это будет работать гораздо быстрее

  • Этот кусок не понятен вообще, зачем два одинаковых запроса

            {
               "fuzzy":{
                  "artist":{
                     "value":"Bill Henderson",
                     "fuzziness":1,
                     "boost":2
                  }
               }
            },
            {
               "fuzzy":{
                  "artist":{
                     "value":"Bill Henderson",
                     "fuzziness":1,
                     "boost":2
                  }
               }
            }
  • Если у вас все поиски происходят по дате, то можно попробовать разбить на несколько индексов (по месяцам или годам) с одной шардой в каждом, и искать только в соответствующем индексе.

#5

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

Именно! Это самый главный вопрос, данной темы: возможно ли увеличить скорость поиска, с помощью асинхронных запросов к Эластику? Как я понял, ваш ответ да?

Протестировано: при синхронных запросах, максимальная скорость достигается установкой количества шард, равного количеству физических ядер CPU.

Готово. Очень интересно ваше мнение по этому поводу.

Для начала важно проверить поиск, где слова в запросе и ответе совпадают, но могут быть с ошибкой, а главное совпадает их количество. Т.е. запрос Fuzzy(1) "Моя Москва" вернёт ответ "Моя Масква", он будет самый релевантный. Если сразу пробуем Match, он вернёт скорее всего, первым результатом "Москва моя Москва Москва", что уже менее релевантно, но score будет выше чем у "Моя Москва", т.к. терм "Москва" встречается в фразе часто. Если не делать Fuzzy, то мы возможно теряем очень релевантный ответ. Возможно я не так решаю эту проблему, но как по другому я не знаю.

Пока не уверен что существующие алгоритмы типа метафона понимают русские слова или хуже: русские слова в транслите.

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


(Igor Motov) #6

Да

Это, скорее всего, из-за того, что у вас все в одном потоке на клиенте.

У меня опыта работы с русским в фонетическом фильтре нет, но русский входит в список поддерживаемых языков, так что было-бы неплохо попробовать. Проблема с fuzzy в том, что это очень тяжелый запрос, что ваши hot threads и подтверждают. Проблему с транслитерацией можно решить применив mapping charfilter при поиске


#7

Доброго дня и с днём программиста!
Остался последний вопрос.

Fuzzy существенно влияет на скорость поиска. Чем этот способ поиска можно заменить? Как я уже писал, нечёткий поиск нужен для того, чтобы найти в индексе точное совпадение с искомой строкой, при условии что 1 - 2 символа могут не совпадать и если результата нет - применять Match.


(Igor Motov) #8

Да. Это происходит потому, что сначала, этот запрос должен найти все совпадения существующие в индексе, которые отличаются от вашего поиска на 1-2 буквы, а потом их искать и этот процесс происходит в каждой шарде. Поэтому уменьшение количества шард, должно уменьшить общую нагрузку и увеличит производительность, если вы будуте запускать по несколько запросов одновременно.

Я на этот вопрос уже ответил. В отличии от fuzzy, когда вы преобразовываете запрос с помощью фонетического анализатора, он производит только один токен и при этом не использует индекс вообще. Это должно быть по скорости сравнимо со скоростью нормального (не fuzzy) поиска.


(system) #9

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.