diff --git a/Kitodo/src/main/java/org/kitodo/production/services/data/BeanQuery.java b/Kitodo/src/main/java/org/kitodo/production/services/data/BeanQuery.java index e667c330345..7eaaea068ab 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/data/BeanQuery.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/data/BeanQuery.java @@ -223,10 +223,17 @@ public void forIdOrInTitle(String searchInput) { * Searches the index and inserts the IDs into the HQL query parameters. */ public void performIndexSearches() { + performIndexSearches(false); + } + + /** + * Searches the index and inserts the IDs into the HQL query parameters. + */ + public void performIndexSearches(boolean useScroll) { for (var iterator = indexQueries.entrySet().iterator(); iterator.hasNext();) { Entry> entry = iterator.next(); Collection ids = indexingService.searchIds(Process.class, entry.getValue().getLeft() - .getSearchField(), entry.getValue().getRight()); + .getSearchField(), entry.getValue().getRight(), useScroll); parameters.put(entry.getKey(), ids.isEmpty() ? NO_HIT : ids); iterator.remove(); } diff --git a/Kitodo/src/main/java/org/kitodo/production/services/data/ProcessService.java b/Kitodo/src/main/java/org/kitodo/production/services/data/ProcessService.java index afd9a8b81a5..0819a96b480 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/data/ProcessService.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/data/ProcessService.java @@ -2411,7 +2411,7 @@ public List getProcessesForExport( query.addBooleanRestriction("project.active", Boolean.TRUE); } query.restrictToClient(sessionClientId); - query.performIndexSearches(); + query.performIndexSearches(true); query.addInnerJoin("project proj"); query.defineSorting("id", SortOrder.ASCENDING); diff --git a/Kitodo/src/main/java/org/kitodo/production/services/index/IndexingService.java b/Kitodo/src/main/java/org/kitodo/production/services/index/IndexingService.java index 7d486da75f1..679fd9ea7cb 100644 --- a/Kitodo/src/main/java/org/kitodo/production/services/index/IndexingService.java +++ b/Kitodo/src/main/java/org/kitodo/production/services/index/IndexingService.java @@ -11,6 +11,7 @@ package org.kitodo.production.services.index; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -20,6 +21,8 @@ import org.apache.logging.log4j.Logger; import org.hibernate.exception.DataException; import org.hibernate.search.engine.search.projection.SearchProjection; +import org.hibernate.search.engine.search.query.SearchScroll; +import org.hibernate.search.engine.search.query.SearchScrollResult; import org.hibernate.search.mapper.orm.Search; import org.hibernate.search.mapper.orm.massindexing.MassIndexer; import org.hibernate.search.mapper.orm.session.SearchSession; @@ -124,23 +127,54 @@ public CompletionStage startIndexing(Class type, MassInde /** * Searches for a search term in a search field and returns the hit IDs. - * + * * @param beanClass * class of beans to search for * @param searchField * search field to search on * @param value * value to be found in the search field + * @param useScroll + * whether to use scrolling (for large result sets like exports) * @return ids of the found beans */ - public Collection searchIds(Class beanClass, String searchField, String value) { + public Collection searchIds(Class beanClass, + String searchField, + String value, + boolean useScroll) { + SearchSession searchSession = Search.session(HibernateUtil.getSession()); - SearchProjection idField = searchSession.scope(beanClass).projection().field("id", Integer.class) + SearchProjection idField = searchSession.scope(beanClass) + .projection() + .field("id", Integer.class) .toProjection(); - List ids = searchSession.search(beanClass).select(idField).where(function -> function.match().field( - searchField).matching(value)).fetchAll().hits(); - logger.debug("Searching {} IDs in field \"{}\" for \"{}\": {} hits", beanClass.getSimpleName(), searchField, - value, ids.size()); + + if (!useScroll) { + List ids = searchSession.search(beanClass) + .select(idField) + .where(f -> f.match().field(searchField).matching(value)) + .fetchAll() + .hits(); + + logger.debug("Searching {} IDs in field \"{}\" for \"{}\": {} hits", + beanClass.getSimpleName(), searchField, value, ids.size()); + return ids; + } + + List ids = new ArrayList<>(); + try (SearchScroll scroll = searchSession.search(beanClass) + .select(idField) + .where(f -> f.match().field(searchField).matching(value)) + .scroll(10_000)) { + SearchScrollResult chunk; + do { + chunk = scroll.next(); + ids.addAll(chunk.hits()); + } while (chunk.hasHits()); + } + + logger.debug("Scrolling {} IDs in field \"{}\" for \"{}\": {} hits", + beanClass.getSimpleName(), searchField, value, ids.size()); return ids; }