Прокрутка страниц Hibernate OGM

давайте предположим, что у нас есть огромная коллекция mongodb (около 60 000 000 записей), и мы хотим прокрутить ее, не извлекая, конечно, огромное количество памяти. Для Hibernate orm это возможно, так как есть прокрутка запросов API и критериев, но что может быть решением для разбиения на страницы в OGM (уже потратил много времени, но я ничего не мог найти)? Я индексирую объекты партиями по 50 000, используя API setFirstResult-setMaxResult. Это время в секундах для получения пакетов из запроса, например

em.createNativeQuery(query, Entity.class).setFirstResult(i).setMaxResults(batchSize).getResultList()
results.stream().forEach(res -> fullTextEntityManager.index(res));

увеличивая i на каждой итерации с помощью i+=batchSize;

Я уже пытался использовать OgmMassIndexer, но мне нужно иметь возможность запускать и останавливать, индексировать определенные диапазоны, поэтому я предпочитаю делать это вручную.

Как очевидно и логично, время на поиск первого результата в каждой итерации увеличивается. Здесь у меня есть время в секундах, чтобы найти следующую партию 50000 с начала из 4 миллионов (setFirstResult(4000000).setMaxResult(50000)):

например. чтобы перейти к 4000000, потребовалось 17 секунд и т. д., чтобы перейти к 4050000, потребовалось 15 секунд и т. д., чтобы перейти к 4100000, потребовалось 12 секунд и т. д., но позже это число значительно увеличивается:

Найдено: 17 Найдено: 15 Найдено: 12 Найдено: 13 Найдено: 13 Найдено: 13 Найдено: 15 Найдено: 16 Найдено: 16 Найдено: 17 Найдено: 18 Найдено: 18 Найдено: 19 Найдено: 19 Найдено: 20 Найдено: 20 Найдено: 21 Найдено: 21 Найдено: 22 Найдено: 21 Найдено: 22 Найдено: 23 Найдено: 23 Найдено: 23 Найдено: 24 Найдено: 24 Найдено: 25 Найдено: 25 Найдено: 26 Найдено: 26 Найдено: 27 Найдено: 28 Найдено: 27 Найдено : 29 Найдено: 29 Найдено: 30 Найдено: 31 Найдено: 32 Найдено: 33 Найдено: 30 Найдено: 33 Найдено: 32 Найдено: 34 Найдено: 34 Найдено: 35 Найдено: 35 Найдено: 38 Найдено: 36 Найдено: 38 Найдено: 36 Найдено: 41 Найдено: 41 Найдено: 39 Найдено: 41 Найдено: 41 Найдено: 40 Найдено: 42 Найдено: 43 Найдено: 42 Найдено: 44 Найдено: 44 Найдено: 45 Найдено: 47 Найдено: 45 Найдено: 44 Найдено: 44 Найдено: 47 Найдено: 44 Найдено: 47 Найдено: 47 Найдено: 50 Найдено: 52 Найдено: 93

Любые варианты прокрутки mongodb с помощью курсора ogm или чего-то еще для извлечения объектов в сеансе и их эффективного индексирования? Я имею в виду, что это нецелесообразно даже для приложения, которое хочет разбить такой большой объем данных на страницы с помощью OGM без Hibernate Search, поэтому я полагаю, что есть решение, которого я не вижу.

Большое спасибо.

Hibernate OGM 5.3.1, Hibernate Search 5.9.0 с использованием ElasticSearch


person Panos    schedule 12.04.2018    source источник
comment
Привет, из любопытства, что за запрос у тебя?   -  person Davide    schedule 12.04.2018
comment
В принципе, мне интересно, что поля, участвующие в запросе, индексируются (я имею в виду, что БД проиндексирована, а не поиск)   -  person Davide    schedule 12.04.2018
comment
TypedQuery‹Entity› query = em.createQuery(SELECT entity FROM Entity entity, Entity.class); Строковый запрос = db.entity_collection.find({ $query: {}, $orderby: { _id : -1 } }); для извлечения в обратном порядке. Это два запроса, которые я пробовал, и еще несколько, использующих собственные запросы. Результат всегда был один. Я думаю, второе, что _id индексируется, это то, что вы имеете в виду. Затем для получения результатов партиями я использую способ, упомянутый выше.   -  person Panos    schedule 13.04.2018


Ответы (3)


Прокрутка пока не поддерживается в OGM, так как для нее требуется Criteria API, который не поддерживается.

При этом вы можете реализовать свой процесс по-разному.

Я собираюсь предположить, что процесс, который становится все медленнее и медленнее, происходит из части запросов (MongoDB все труднее и труднее найти N-й результат), а не из части индексации (Elasticsearch все труднее и труднее добавлять документы в индекс) .

Если это так, вы можете попробовать «кусковые» запросы вместо разбиения на страницы. Идея состоит в том, чтобы сначала получить первый и последний идентификатор для типа объекта, который вы хотите проиндексировать, а затем вместо использования нумерации страниц выполнять запросы с условием, подобным where ID between <last ID in the previous query + 1> AND <last ID in the previous query + page size>.

При условии, что поле ID имеет восходящий индекс в MongoDB, это должно избавиться от ухудшения производительности с течением времени.

person yrodiere    schedule 12.04.2018
comment
Еще не пробовал, но кажется возможным решением моей проблемы. Моя реализация будет использовать Hibernate Search, конечно, после индексации данных для быстрой разбивки на страницы. Я просто хотел убедиться, что я ничего не упускаю :). Большое спасибо! - person Panos; 13.04.2018

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

ГК

Первый подозреваемый заключается в том, что вашей JVM не хватает памяти; Я подозреваю, что драйвер MongoDB/Java может удерживать некоторые данные, возможно, больше, чем мы ожидали. Не могли бы вы включить ведение журнала GC на JVM, чтобы проверить, как она себя ведет, или подключить какой-либо профилировщик, чтобы увидеть, остается ли использование памяти в разумных пределах в течение всего процесса.

Размер индекса

Любой индекс Lucene или Elasticsearch будет немного замедляться во время записи, пока он растет. Это замедление не должно быть очень значительным, поэтому я не думаю, что это то, что вы наблюдаете, но чтобы убедиться, что сам процесс индексации не мешает вам попробовать запустить тот же процесс с черной дырой бэкенд.

hibernate.search.default.worker.backend blackhole

Н.Б. для этого свойства требуется не использовать менеджер индексов Elasticsearch, поэтому вам придется временно переключить конфигурацию Hibernate Search в режим индексирования Lucene по умолчанию.

Загрузка из MongoDB

Это наиболее вероятная проблема, и я прислушаюсь к прекрасному предложению Йоанна по этому поводу, просто убедитесь, что это действительно проблема, сначала проверив предыдущие два пункта.

person Sanne    schedule 12.04.2018
comment
Проверил gc в visual vm-gc, все в порядке. Использовал черную дыру и все равно. Проблема заключается в том, чтобы найти n-й элемент, я уверен и, вероятно, буду использовать решение Йоанна. Спасибо большое Санне. - person Panos; 13.04.2018

В качестве альтернативного решения, в дополнение к упомянутому ранее, вы также можете расширить MongoDBDialect и переопределить метод forEachTuple.

Это тот, который извлекает данные для индексирования, поэтому, если вы заранее знаете, как фильтровать нужные вам данные, это может быть решением.

Затем вы можете использовать свой новый диалект, установив свойство: hibernate.ogm.datastore.grid_dialect

Метод Foreach: https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/main/java/org/hibernate/ogm/datastore/mongodb/MongoDBDialect.java#L848

Текущий поставщик: https://github.com/hibernate/hibernate-ogm/blob/master/mongodb/src/main/java/org/hibernate/ogm/datastore/mongodb/MongoDBDialect.java#L1924< /а>

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

person Davide    schedule 12.04.2018
comment
Кажется, что это самое сложное для меня, я так думаю, что пока я буду придерживаться решения Йоанна, хотя это полезно знать. Спасибо, Давид :) - person Panos; 13.04.2018
comment
Определенно да. Я бы оставил его в крайнем случае, и я упомянул его здесь на случай, если это может помочь другим. Ваше здоровье - person Davide; 16.04.2018
comment
ОБНОВЛЕНИЕ: в конце я использую ваш способ, так как есть необходимость в использовании курсора. Работает отлично, используя Tuple next() MongoDBResultsCursor, чтобы сначала переместить курсор в точку, где я остановил индекс (последняя отметка времени, которая была проиндексирована, это занимает некоторое время), а затем я продолжаю быстро использовать massIndexer с этой точки. Довольно надежное решение для моей проблемы и проще, чем кажется. Еще раз большое спасибо! - person Panos; 20.04.2018