Проблемы производительности JMS Serializer с более чем 10000 записей

В настоящее время я создаю команду PHP, которая может обновлять мои индексы ElasticSearch.

Но я заметил одну важную вещь: сериализация сущностей, когда мой массив содержит более 10000 из них, занимает слишком много времени. Я думал, что это будет линейно, но 6 или 9 тысяч сущностей занимают около минуты (нет большой разницы между 6 или 9 тысячами), но когда вы проходите 10 тысяч, это просто замедляется до такой степени, что занимает до 10 минут.

...
                // we iterate on the documents previously requested to the sql database
                foreach($entities as $index_name => $entity_array) {
                    $underscoreClassName = $this->toUnderscore($index_name); // elasticsearch understands underscored names
                    $camelcaseClassName = $this->toCamelCase($index_name); // sql understands camelcase names

                    // we get the serialization groups for each index from the config file
                    $groups = $indexesInfos[$underscoreClassName]['types'][$underscoreClassName]['serializer']['groups']; 

                    foreach($entity_array as $entity) {
                        // each entity is serialized as a json array
                        $data = $this->serializer->serialize($entity, 'json', SerializationContext::create()->setGroups($groups));
                        // each serialized entity as json is converted as an Elastica document
                        $documents[$index_name][] = new \Elastica\Document($entityToFind[$index_name][$entity->getId()], $data);
                    }
                }
...

Вокруг этого целый класс, но это то, что занимает большую часть времени.

Я понимаю, что сериализация — сложная операция и требует времени, но почему почти нет разницы между 6, 7, 8 или 9k, но когда более 10k сущностей, это занимает много времени?

PS: Для справки: я открыл вопрос на github.

РЕДАКТИРОВАТЬ :

Чтобы объяснить, что я пытаюсь сделать более точно, у нас есть база данных SQL в проекте Symfony, используем Doctrine для связывания обоих, и мы используем ElasticSearch (и пакеты FOSElastica и Elastica) для индексации наших данных в ElasticSearch.

Дело в том, что в то время как FOSElastica заботится об обновлении данных, которые обновляются в базе данных SQL, она не обновляет каждый индекс, содержащий эти данные. (Например, если у вас есть автор и две книги, которые он написал, в ES у вас будут две книги с автором и автором. FOSElastica обновляет только автора, а не информацию об авторе в двух книгах. ).

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

РЕДАКТИРОВАТЬ :

Чтобы добавить больше информации о том, что я пробовал, у меня возникла та же проблема при использовании команды «заполнить» из FOSElastica. Когда 9к, то все нормально и плавно, а когда 10к, то очень долго.

В настоящее время я запускаю тест с уменьшением размера моего массива в моем скрипте и его сбросом, пока не повезло.


person Malcom HAMELIN    schedule 17.07.2019    source источник


Ответы (2)


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

У вас есть либо 2 решения: используйте генератор, чтобы избежать создания этого массива, ИЛИ попробуйте отправить свои документы каждые «x» итераций и сбросить свой массив.

Я надеюсь, что это дало вам представление о том, как обрабатывать такого рода миграции.

Кстати, я почти забыл сказать вам, чтобы вы избегали использования репозиториев ORM/ODM для извлечения данных (в сценариях миграции). Проблема в том, что они будут использовать объекты и гидратировать их, и, честно говоря, в огромных сценариях миграции вы просто будете вечно ждать ничего. Если возможно, просто используйте объект базы данных, которого, вероятно, будет достаточно для того, что вы хотите сделать.

person millenion    schedule 17.07.2019
comment
Это логично, я догадывался, что в этом что-то есть. Я должен просто проверить это и вернуться сюда. - person Malcom HAMELIN; 17.07.2019
comment
Кстати: использование ORM/ODM в сценарии миграции — ужасная идея. Если вы используете пакет миграции доктрины, просто используйте объект подключения к базе данных для извлечения записей в вашей базе данных в их стиле массива. Гидратация и создание объектов через ODM действительно не предназначены для использования в сценариях такого размера. - person millenion; 17.07.2019
comment
Я не думаю, что это можно назвать скриптом миграции, но я вообще не объяснил, что это такое, так что я отредактирую свой пост и попытаюсь объяснить, что именно я пытаюсь сделать. - person Malcom HAMELIN; 17.07.2019
comment
Привет, просто вопрос: вы удалили автокоммит elasticsearch? У нас были почти такие же проблемы в одном из проектов, над которым я работал, и это действительно помогло нам улучшить наши показатели. И, кстати, попробуйте профилировать свой код с помощью Blackfire, вы точно увидите, где ваше узкое место. Попробуйте это сначала, если это возможно. Это действительно быстро настроить, а затем использовать, даже в режиме CLI. - person millenion; 18.07.2019
comment
Здравствуйте, я не удалял это, что вы подразумеваете под автоматической фиксацией ElasticSearch? Я ничего не могу найти по этому поводу, можно ссылку на документ? Хороший звонок о Blackfire, я не знал о нем, спасибо, это кажется действительно хорошим инструментом. - person Malcom HAMELIN; 19.07.2019
comment
Привет, извините, настоящее слово для этого в elasticsearch — «обновление»: это означает, что при каждом нажатии ваш индекс будет обновляться, чтобы учитывать новые документы. Во время массовых операций это может быть проблематично. Идея состоит в том, чтобы отключить это поведение во время массовых операций, а затем вернуть его после завершения. Вы можете проверить это здесь: elastic.co/ руководство/en/elasticsearch/reference/current/ - person millenion; 20.07.2019

Я изменил способ работы своего алгоритма и сначала получаю все идентификаторы, которые необходимо обновить, а затем получаю их из базы данных партиями по 500-1000 (я провожу тесты).

                    /*
                    * to avoid creating arrays with too much objects, we loop on the ids and split them by DEFAULT_BATCH_SIZE
                    * this way we get them by packs of DEFAULT_BATCH_SIZE and add them by the same amount
                    */ 
                    for ($i = 0 ; $i < sizeof($idsToRequest) ; $i++) {
                        $currentSetOfIds[] = $idsToRequest[$i]; 

                        // every time we have DEFAULT_BATCH_SIZE ids or if it's the end of the loop we update the documents
                        if ($i % self::DEFAULT_BATCH_SIZE == 0 || $i == sizeof($idsToRequest)-1) {
                            if ($currentSetOfIds) {

                                // retrieves from the database a batch of entities
                                $entities = $thatRepo->findBy(array('id' => $currentSetOfIds)); 

                                // serialize and create documents with the entities we got earlier
                                foreach($entities as $entity) {
                                    $data = $this->serializer->serialize($entity, 'json', SerializationContext::create()->setGroups($groups));
                                    $documents[] = new \Elastica\Document($entityToFind[$indexName][$entity->getId()], $data);
                                }

                                // update all the documents serialized
                                $elasticaType->updateDocuments($documents);

                                // reset of arrays
                                $currentSetOfIds = [];
                                $documents = [];
                            }
                        }
                    }

Я обновляю их на ту же сумму, но это все еще не улучшает производительность метода сериализации. Я действительно не понимаю, как сериализатор может так отличаться от того, что у меня есть 9 или 10 тысяч сущностей, когда он никогда не знает об этом...

person Malcom HAMELIN    schedule 18.07.2019