From f4484f6409b0a2c621c4928a4735dba57a2233fd Mon Sep 17 00:00:00 2001 From: Junghoon Ban Date: Thu, 6 Jun 2024 20:10:04 +0900 Subject: [PATCH] Add support for pagination setting. Closes #121 --- .../meilisearch/annotations/Pagination.java | 40 +++++++++++++++++++ .../data/meilisearch/annotations/Setting.java | 34 +++++++++++++++- .../core/MeilisearchOperations.java | 3 +- .../SimpleMeilisearchPersistentEntity.java | 7 ++++ .../entities/TotalHitsLimited.java | 36 +++++++++++++++++ ...MeilisearchRepositoryIntegrationTests.java | 23 ++++++++++- 6 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/vanslog/spring/data/meilisearch/annotations/Pagination.java create mode 100644 src/test/java/io/vanslog/spring/data/meilisearch/entities/TotalHitsLimited.java diff --git a/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Pagination.java b/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Pagination.java new file mode 100644 index 00000000..2fbc2a3b --- /dev/null +++ b/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Pagination.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.vanslog.spring.data.meilisearch.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.data.annotation.Persistent; + +/** + * Meilisearch Pagination + * + * @author Junghoon Ban + */ +@Persistent +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE }) +public @interface Pagination { + + /** + * The maximum number of search results Meilisearch can return + */ + int maxTotalHits() default 1000; +} diff --git a/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Setting.java b/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Setting.java index 9247502b..f89e4f46 100644 --- a/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Setting.java +++ b/src/main/java/io/vanslog/spring/data/meilisearch/annotations/Setting.java @@ -26,6 +26,7 @@ * Meilisearch Setting * * @author Junghoon Ban + * @see Settings */ @Persistent @Inherited @@ -34,19 +35,50 @@ public @interface Setting { /** - * attributes to define an index sorting + * attributes to be used for sorting + * @see Sortable attributes */ String[] sortAttributes() default {}; + /** + * attributes to be used for filtering + * @see Filterable attributes + */ String[] filterableAttributes() default {}; + /** + * defines the ranking rules + * @see Ranking rules + */ String distinctAttribute() default ""; + /** + * attributes to be used for searching + * @see Searchable attributes + */ String[] searchableAttributes() default { "*" }; + /** + * attributes to be displayed in the search results + * @see Displayed attributes + */ String[] displayedAttributes() default { "*" }; + /** + * defines the ranking rules + * @see Ranking rules + */ String[] rankingRules() default { "words", "typo", "proximity", "attribute", "sort", "exactness" }; + /** + * defines the stop words + * @see Stop words + */ String[] stopWords() default {}; + + /** + * defines the pagination behavior + * @see Pagination + */ + Pagination pagination() default @Pagination; } diff --git a/src/main/java/io/vanslog/spring/data/meilisearch/core/MeilisearchOperations.java b/src/main/java/io/vanslog/spring/data/meilisearch/core/MeilisearchOperations.java index 2638ea08..4c8d6081 100644 --- a/src/main/java/io/vanslog/spring/data/meilisearch/core/MeilisearchOperations.java +++ b/src/main/java/io/vanslog/spring/data/meilisearch/core/MeilisearchOperations.java @@ -174,7 +174,8 @@ public interface MeilisearchOperations { /** * Search for entities that meet the criteria using the given {@link SearchRequest}. Note that by default, - * {@literal MaxTotalHits} in {@link com.meilisearch.sdk.model.Pagination} is 1000. + * {@literal MaxTotalHits} in {@link io.vanslog.spring.data.meilisearch.annotations.Pagination} is 1000. If you want + * to change the value, you can use {@link io.vanslog.spring.data.meilisearch.annotations.Setting}. * * @param searchRequest the search request * @param clazz the entity class, must be annotated with diff --git a/src/main/java/io/vanslog/spring/data/meilisearch/core/mapping/SimpleMeilisearchPersistentEntity.java b/src/main/java/io/vanslog/spring/data/meilisearch/core/mapping/SimpleMeilisearchPersistentEntity.java index 9ded7cdb..7048f1d4 100644 --- a/src/main/java/io/vanslog/spring/data/meilisearch/core/mapping/SimpleMeilisearchPersistentEntity.java +++ b/src/main/java/io/vanslog/spring/data/meilisearch/core/mapping/SimpleMeilisearchPersistentEntity.java @@ -18,6 +18,7 @@ import com.meilisearch.sdk.model.Settings; import io.vanslog.spring.data.meilisearch.annotations.Document; +import io.vanslog.spring.data.meilisearch.annotations.Pagination; import io.vanslog.spring.data.meilisearch.annotations.Setting; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -114,6 +115,7 @@ private void processSettingAnnotation(Setting settingAnnotation, SettingsParamet settingsParameter.searchableAttributes = settingAnnotation.searchableAttributes(); settingsParameter.displayedAttributes = settingAnnotation.displayedAttributes(); settingsParameter.rankingRules = settingAnnotation.rankingRules(); + settingsParameter.pagination = settingAnnotation.pagination(); String[] sortAttributes = settingAnnotation.sortAttributes(); String[] filterableAttributes = settingAnnotation.filterableAttributes(); @@ -145,6 +147,7 @@ private static class SettingsParameter { private String[] displayedAttributes; private String[] rankingRules; @Nullable private String[] stopWords; + private Pagination pagination; Settings toSettings() { Settings settings = new Settings(); @@ -168,6 +171,10 @@ Settings toSettings() { settings.setStopWords(stopWords); } + var meiliPagination = new com.meilisearch.sdk.model.Pagination(); + meiliPagination.setMaxTotalHits(this.pagination.maxTotalHits()); + settings.setPagination(meiliPagination); + return settings; } } diff --git a/src/test/java/io/vanslog/spring/data/meilisearch/entities/TotalHitsLimited.java b/src/test/java/io/vanslog/spring/data/meilisearch/entities/TotalHitsLimited.java new file mode 100644 index 00000000..c37a6d1c --- /dev/null +++ b/src/test/java/io/vanslog/spring/data/meilisearch/entities/TotalHitsLimited.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.vanslog.spring.data.meilisearch.entities; + +import io.vanslog.spring.data.meilisearch.annotations.Document; +import io.vanslog.spring.data.meilisearch.annotations.Pagination; +import io.vanslog.spring.data.meilisearch.annotations.Setting; +import org.springframework.data.annotation.Id; + +/** + * Pagination entity for tests. + * It is set to have a maximum of 10 total hits. + */ +@Document(indexUid = "total-hits-limited") +@Setting( + sortAttributes = { "name" }, + pagination = @Pagination(maxTotalHits = 10) +) +public class TotalHitsLimited { + @Id + public int id; + public String name; +} diff --git a/src/test/java/io/vanslog/spring/data/meilisearch/repository/MeilisearchRepositoryIntegrationTests.java b/src/test/java/io/vanslog/spring/data/meilisearch/repository/MeilisearchRepositoryIntegrationTests.java index b4156fc3..9ab7b49d 100644 --- a/src/test/java/io/vanslog/spring/data/meilisearch/repository/MeilisearchRepositoryIntegrationTests.java +++ b/src/test/java/io/vanslog/spring/data/meilisearch/repository/MeilisearchRepositoryIntegrationTests.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.*; import io.vanslog.spring.data.meilisearch.entities.Movie; +import io.vanslog.spring.data.meilisearch.entities.TotalHitsLimited; import io.vanslog.spring.data.meilisearch.junit.jupiter.MeilisearchTest; import io.vanslog.spring.data.meilisearch.junit.jupiter.MeilisearchTestConfiguration; import io.vanslog.spring.data.meilisearch.repository.config.EnableMeilisearchRepositories; @@ -45,6 +46,7 @@ class MeilisearchRepositoryIntegrationTests { @Autowired private MovieRepository movieRepository; + @Autowired private TotalHitsLimitedRepository totalHitsLimitedRepository; @BeforeEach void setUp() { @@ -335,7 +337,6 @@ void shouldFindDocumentsWithSorting() { assertThat(ascOrdered).hasSize(3).containsExactly(movie1, movie3, movie2); } - @Test void shouldFindDocumentsWithPagingAndSorting() { // given @@ -380,9 +381,29 @@ void shouldFindDocumentsWithPagingAndSorting() { assertThat(page2.getContent().get(0)).isEqualTo(movie2); } + @Test + void shouldNotSearchAllElementsWhenMaxTotalHitsAre10() { + // given + int elementCount = 11; + + for (int i = 0; i < elementCount; i++) { + TotalHitsLimited entity = new TotalHitsLimited(); // It is limited to 10 hits. + entity.id = i; + entity.name = "name" + i; + totalHitsLimitedRepository.save(entity); + } + + // when + Page page = totalHitsLimitedRepository.findAll(PageRequest.of(0, elementCount)); + + // then + assertThat(page).hasSizeLessThan(elementCount); + } interface MovieRepository extends MeilisearchRepository {} + interface TotalHitsLimitedRepository extends MeilisearchRepository {} + @Configuration @Import(MeilisearchTestConfiguration.class) @EnableMeilisearchRepositories(basePackages = "io.vanslog.spring.data.meilisearch.repository",