Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
package com.company.demo.service;

import io.jmix.search.searching.SearchRequestContext;
import io.jmix.searchopensearch.searching.strategy.OpenSearchSearchStrategy;
import io.jmix.searchopensearch.searching.strategy.OpenSearchQueryConfigurer;
import io.jmix.searchopensearch.searching.strategy.impl.AbstractOpenSearchStrategy;
import org.opensearch.client.opensearch._types.query_dsl.Operator;
import org.opensearch.client.opensearch.core.SearchRequest;
import org.springframework.stereotype.Component;

// tag::strategy[]
@Component
public class CustomOpenSearchSearchStrategy implements OpenSearchSearchStrategy {
public class CustomOpenSearchSearchStrategy extends AbstractOpenSearchStrategy {

public CustomOpenSearchSearchStrategy(OpenSearchQueryConfigurer queryConfigurer) {
super(queryConfigurer); // <1>
}

@Override
public String getName() {
return "CustomStrategy";
return "CustomStrategy"; // <2>
}

@Override
public void configureRequest(SearchRequestContext<SearchRequest.Builder> searchRequestContext) {
//configure your request
searchRequestContext.getRequestBuilder().query(queryBuilder ->
queryBuilder.multiMatch(multiMatchQueryBuilder ->
multiMatchQueryBuilder.fields("*")
.query(searchRequestContext.getSearchContext().getSearchText())
)
public void configureRequest(SearchRequestContext<SearchRequest.Builder> requestContext) { // <3>
queryConfigurer.configureRequest( // <4>
requestContext,
(queryBuilder, scope) -> // <5>
queryBuilder.multiMatch(multiMatchQueryBuilder ->
multiMatchQueryBuilder
.fields(scope.getFieldList()) // <6>
.query(requestContext.getSearchContext().getEscapedSearchText())
.operator(Operator.Or)
)
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion content/modules/search/pages/search-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ The Search add-on provides an MBean with `jmix.search:type=EntityIndexing` objec

Data access control is performed by the Search add-on in two steps:

* Pre-search - checks xref:security:resource-roles.adoc#entity-policy[entity policies] and excludes indexes related to forbidden entities.
* Pre-search - checks xref:security:resource-roles.adoc#entity-policy[entity policies] and excludes indexes related to forbidden entities. Since Jmix 2.7, xref:security:resource-roles.adoc#entity-attribute-policy[attribute policies] are applied as well: only entity attributes that the current user is allowed to read are included in the search query, so matches in restricted attributes are not returned. If the current user has no access to any of the requested entities, the search returns an empty result.

* Post-search - checks if there are any xref:security:row-level-roles.adoc#policies[row-level policies] configured for found entities. If they exist, the found instances are reloaded to apply security policies.

Expand Down
23 changes: 15 additions & 8 deletions content/modules/search/pages/search-in-ui.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,28 @@ include::example$/search-ex1/src/main/resources/application.properties[tags=defa
[[custom-search-strategies]]
=== Custom Search Strategies

Additionally, you can create a custom search strategy. For that purpose, you need to create a new Spring bean implementing one of the platform-specific interfaces:
Additionally, you can create a custom search strategy. Create a Spring bean that extends one of the platform-specific base classes:

* `OpenSearchSearchStrategy` - if you use OpenSearch.
* `ElasticsearchSearchStrategy` - if you use Elasticsearch.
* `AbstractOpenSearchStrategy` - if you use OpenSearch.
* `AbstractElasticSearchStrategy` - if you use Elasticsearch.

Then you need to implement 2 methods:

* `String getName()` - should return a unique strategy name.

* `void configureRequest(SearchRequest.Builder requestBuilder, SearchContext searchContext)` - configure your search request using the provided builder according to your requirements.
Implement `getName()` and `configureRequest(SearchRequestContext)`:

[source,java,indent=0]
----
include::example$/search-ex1/src/main/java/com/company/demo/service/CustomOpenSearchSearchStrategy.java[tags=strategy]
----
<1> The base class is initialized with the platform-specific query configurer (`OpenSearchQueryConfigurer` or `ElasticSearchQueryConfigurer`), available as the `queryConfigurer` field.
<2> `getName()` returns a unique strategy name used to select the strategy.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add something about configureRequest method

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

<3> `configureRequest(SearchRequestContext)` is the method the search engine invokes for the strategy — implement it to build the search request.
<4> Build the query through `queryConfigurer.configureRequest()`. The configurer resolves the search scope - the target indexes and the fields the current user is permitted to read - and applies security policies.
<5> The lambda receives the platform-specific query builder and the resolved `IndexSearchRequestScope`.
<6> Use `scope.getFieldList()` to search only the permitted fields.

[NOTE]
====
Always build the query through `queryConfigurer`. If you configure the request builder directly (for example, with `fields("*")`), the search scope is not resolved and xref:security:resource-roles.adoc#entity-attribute-policy[attribute policies] are not applied, which can make the search return no results.
====

After that, you can assign your custom strategy to the xref:search-field-component.adoc[SearchField] or xref:full-text-filter-component.adoc[FullTextFilter] component using the strategy name.

Expand Down
13 changes: 13 additions & 0 deletions content/modules/whats-new/pages/release-3.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,19 @@ Getter return types changed in the following properties:

See https://github.com/jmix-framework/jmix/issues/5262[#5262^] for more information.

[[search-breaking-changes]]
=== Search

The search strategy API and helper classes deprecated in 2.7 have been removed:

* The `configureRequest(SearchRequest.Builder, SearchContext)` method of `ElasticsearchSearchStrategy` / `OpenSearchSearchStrategy`. Implement `configureRequest(SearchRequestContext)` instead and build the query through the platform-specific `ElasticSearchQueryConfigurer` / `OpenSearchQueryConfigurer`.

* The `SearchUtils` class. Use `SearchRequestScopeProvider`, `SearchFieldsProvider`, and `SearchSecurityDecorator` instead.

If you implemented a custom search strategy, migrate it to the new API — see xref:search:search-in-ui.adoc#custom-search-strategies[Custom Search Strategies].

See https://github.com/jmix-framework/jmix/issues/4866[#4866^] for more information.

[[removed-dependencies]]
=== Removed Dependencies

Expand Down