This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 72f46ce43c02d8680ca116d4f62340193ffaff27
Author: Quan Tran <[email protected]>
AuthorDate: Thu Jan 29 15:25:09 2026 +0700

    JAMES-4166 JMAP search: drop scroll search, use from/size pagination and 
collapse by messageId
---
 .../OpenSearchListeningMessageSearchIndex.java     |  6 +--
 .../opensearch/search/OpenSearchSearcher.java      | 44 ++++++++++++++++++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
index c88bd7dba7..15a3227a99 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/events/OpenSearchListeningMessageSearchIndex.java
@@ -369,10 +369,8 @@ public class OpenSearchListeningMessageSearchIndex extends 
ListeningMessageSearc
             return Flux.empty();
         }
 
-        return searcher.search(mailboxIds, searchQuery, Optional.empty(), 
MESSAGE_ID_FIELD, !SEARCH_HIGHLIGHT)
-            .handle(this::extractMessageIdFromHit)
-            .distinct()
-            .take(limit);
+        return searcher.searchCollapsedByMessageId(mailboxIds, searchQuery, 
Math.toIntExact(limit), MESSAGE_ID_FIELD, !SEARCH_HIGHLIGHT)
+            .handle(this::extractMessageIdFromHit);
     }
 
     @Override
diff --git 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
index 3d61f747a8..d11bdf8333 100644
--- 
a/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
+++ 
b/mailbox/opensearch/src/main/java/org/apache/james/mailbox/opensearch/search/OpenSearchSearcher.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox.opensearch.search;
 
 import static 
org.apache.james.mailbox.opensearch.search.OpenSearchSearchHighlighter.ATTACHMENT_TEXT_CONTENT_FIELD;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
@@ -104,6 +105,22 @@ public class OpenSearchSearcher {
             .searchHits();
     }
 
+    public Flux<Hit<ObjectNode>> 
searchCollapsedByMessageId(Collection<MailboxId> mailboxIds, SearchQuery query,
+                                                            int limit, 
List<String> fields,
+                                                            boolean 
searchHighlight) {
+        if (limit == 0) {
+            return Flux.empty();
+        }
+
+        SearchRequest searchRequest = 
prepareCollapsedSearchByMessageId(mailboxIds, query, 0, limit, fields, 
searchHighlight);
+        try {
+            return client.search(searchRequest)
+                .flatMapMany(response -> 
Flux.fromIterable(response.hits().hits()));
+        } catch (IOException e) {
+            return Flux.error(e);
+        }
+    }
+
     private SearchRequest prepareSearch(Collection<MailboxId> mailboxIds, 
SearchQuery query,
                                         Optional<Integer> limit, List<String> 
fields, boolean highlight) {
         List<SortOptions> sorts = query.getSorts()
@@ -130,6 +147,33 @@ public class OpenSearchSearcher {
             .build();
     }
 
+    private SearchRequest 
prepareCollapsedSearchByMessageId(Collection<MailboxId> mailboxIds, SearchQuery 
query,
+                                                            int from, int 
size, List<String> fields, boolean highlight) {
+        List<SortOptions> sorts = query.getSorts()
+            .stream()
+            .flatMap(SortConverter::convertSort)
+            .map(fieldSort -> new 
SortOptions.Builder().field(fieldSort).build())
+            .collect(Collectors.toList());
+
+        SearchRequest.Builder request = new SearchRequest.Builder()
+            .index(aliasName.getValue())
+            .query(queryConverter.from(mailboxIds, query))
+            .from(from)
+            .size(size)
+            .storedFields(fields)
+            .sort(sorts)
+            .collapse(collapse -> 
collapse.field(JsonMessageConstants.MESSAGE_ID));
+
+        if (highlight) {
+            request.highlight(highlightQuery);
+        }
+
+        return toRoutingKey(mailboxIds)
+            .map(request::routing)
+            .orElse(request)
+            .build();
+    }
+
     private Optional<String> toRoutingKey(Collection<MailboxId> mailboxIds) {
         if (mailboxIds.size() < MAX_ROUTING_KEY) {
             return Optional.of(mailboxIds.stream()


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to