diff --git a/api/src/main/java/run/halo/app/search/SearchOption.java b/api/src/main/java/run/halo/app/search/SearchOption.java index 2c0edf6ba..1c84ce430 100644 --- a/api/src/main/java/run/halo/app/search/SearchOption.java +++ b/api/src/main/java/run/halo/app/search/SearchOption.java @@ -53,22 +53,22 @@ public class SearchOption { private Boolean filterPublished; /** - * Types to include. If null, it will include all types. + * Types to include(or). If null, it will include all types. */ private List includeTypes; /** - * Owner names to include. If null, it will include all owners. + * Owner names to include(or). If null, it will include all owners. */ private List includeOwnerNames; /** - * Category names to include. If null, it will include all categories. + * Category names to include(and). If null, it will include all categories. */ private List includeCategoryNames; /** - * Tag names to include. If null, it will include all tags. + * Tag names to include(and). If null, it will include all tags. */ private List includeTagNames; diff --git a/application/src/main/java/run/halo/app/search/lucene/LuceneSearchEngine.java b/application/src/main/java/run/halo/app/search/lucene/LuceneSearchEngine.java index 42698cc42..b8e54fde7 100644 --- a/application/src/main/java/run/halo/app/search/lucene/LuceneSearchEngine.java +++ b/application/src/main/java/run/halo/app/search/lucene/LuceneSearchEngine.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import lombok.extern.slf4j.Slf4j; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.charfilter.HTMLStripCharFilterFactory; @@ -170,6 +171,45 @@ public class LuceneSearchEngine implements SearchEngine, InitializingBean, Dispo new TermQuery(new Term("published", filterPublished.toString())), FILTER ); } + + Optional.ofNullable(option.getIncludeTypes()) + .filter(types -> !types.isEmpty()) + .ifPresent(types -> { + var typeTerms = types.stream() + .distinct() + .map(BytesRef::new) + .toList(); + queryBuilder.add(new TermInSetQuery("type", typeTerms), FILTER); + }); + + Optional.ofNullable(option.getIncludeOwnerNames()) + .filter(ownerNames -> !ownerNames.isEmpty()) + .ifPresent(ownerNames -> { + var ownerTerms = ownerNames.stream() + .distinct() + .map(BytesRef::new) + .toList(); + queryBuilder.add(new TermInSetQuery("ownerName", ownerTerms), FILTER); + }); + + Optional.ofNullable(option.getIncludeTagNames()) + .filter(tagNames -> !tagNames.isEmpty()) + .ifPresent(tagNames -> tagNames + .stream() + .distinct() + .forEach(tagName -> + queryBuilder.add(new TermQuery(new Term("tag", tagName)), FILTER) + )); + + Optional.ofNullable(option.getIncludeCategoryNames()) + .filter(categoryNames -> !categoryNames.isEmpty()) + .ifPresent(categoryNames -> categoryNames + .stream() + .distinct() + .forEach(categoryName -> + queryBuilder.add(new TermQuery(new Term("category", categoryName)), FILTER) + )); + var finalQuery = queryBuilder.build(); var limit = option.getLimit(); diff --git a/application/src/test/java/run/halo/app/search/lucene/LuceneSearchEngineIntegrationTest.java b/application/src/test/java/run/halo/app/search/lucene/LuceneSearchEngineIntegrationTest.java index 91e415235..9437af0fe 100644 --- a/application/src/test/java/run/halo/app/search/lucene/LuceneSearchEngineIntegrationTest.java +++ b/application/src/test/java/run/halo/app/search/lucene/LuceneSearchEngineIntegrationTest.java @@ -6,6 +6,7 @@ import static run.halo.app.core.extension.content.Post.VisibleEnum.PRIVATE; import static run.halo.app.core.extension.content.Post.VisibleEnum.PUBLIC; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -122,6 +123,9 @@ public class LuceneSearchEngineIntegrationTest { option.setKeyword("halo"); option.setHighlightPreTag(""); option.setHighlightPostTag(""); + option.setIncludeTagNames(List.of("search")); + option.setIncludeCategoryNames(List.of("halo")); + option.setIncludeOwnerNames(List.of("admin")); retryTemplate.execute(context -> { webClient.post().uri("/apis/api.halo.run/v1alpha1/indices/-/search") .bodyValue(option) @@ -218,6 +222,8 @@ public class LuceneSearchEngineIntegrationTest { spec.setPriority(0); spec.setSlug("/first-post"); spec.setDeleted(false); + spec.setTags(List.of("search")); + spec.setCategories(List.of("halo")); var excerpt = new Post.Excerpt(); excerpt.setRaw("first post description"); excerpt.setAutoGenerate(false);