Using Search in UI
Visual Components
The Search add-on provides two UI components: SearchField
and FullTextFilter
.
These components are available in the Add Component palette of the Studio View Designer as soon as you install the add-on in your project.
If you don’t use the view designer, declare the search
namespace in your view’s XML descriptor manually:
<view xmlns="http://jmix.io/schema/flowui/view"
xmlns:search="http://jmix.io/schema/search/ui"
title="msg://searchView.title">
SearchField
The SearchField
component presents a text input field along with a button for executing searches.
Here’s a usage example of the SearchField
component within a view:
<view xmlns="http://jmix.io/schema/flowui/view"
xmlns:search="http://jmix.io/schema/search/ui"
title="msg://searchView.title">
<layout>
<search:searchField id="searchField"/>
</layout>
</view>
Attributes of the SearchField
component:
-
searchStrategy
- determines the search strategy applied. If no strategy is specified, the default one is used. -
entities
- specifies the entities for searching. Multiple entities can be listed as a comma-separated sequence:<search:searchField id="searchField" entities="Customer, Order_"/>
By default, searchField
opens the built-in SearchResultsView
. This view handles the search engine querying process and presents a result list within the navigation view or in a new dialog, based on the openMode
attribute of searchField
.
If you wish to modify this functionality, you can configure the SearchCompletedHandler
in the following manner:
@Autowired
private DialogWindows dialogWindows;
@ViewComponent
private SearchField searchField;
@Install(to = "searchField", subject = "searchCompletedHandler")
private void searchFieldSearchCompletedHandler(
final SearchField.SearchCompletedEvent event) {
SearchResult searchResult = event.getSearchResult();
DialogWindow<SearchResultsView> searchResultsDialog =
dialogWindows.view(UiComponentUtils.getView(this),
SearchResultsView.class)
.build();
SearchResultsView view = searchResultsDialog.getView();
view.initView(new SearchFieldContext(searchField));
searchResultsDialog.open();
}
Alternatively, you can use the setSearchCompletedHandler()
method of the component.
FullTextFilter
The FullTextFilter
component functions similarly to the propertyFilter component.
Here’s an example of using fullTextFilter
in the view:
<data>
<collection id="ordersDc"
class="com.company.demo.entity.Order">
<loader id="ordersDl"
readOnly="true">
<query>
<![CDATA[select e from Order_ e]]>
</query>
</loader>
<fetchPlan extends="_base">
<property name="customer"
fetchPlan="_base"/>
</fetchPlan>
</collection>
</data>
<layout>
<search:fullTextFilter dataLoader="ordersDl"
autoApply="true"/>
<dataGrid id="ordersDataGrid"
width="100%"
dataContainer="ordersDc">
<columns>
<column property="number"/>
<column property="date"/>
<column property="amount"/>
<column property="product"/>
</columns>
</dataGrid>
</layout>
Attributes of the FullTextFilter
component:
-
dataLoader
specifies theDataLoader
to be filtered. -
searchStrategy
determines the search strategy to be employed. If not explicitly defined, a default strategy is utilized. -
autoApply
- when set totrue
, theFullTextFilter
component automatically applies itself to theDataLoader
upon changes to its value.
FullTextFilter
works as follows: it finds identifiers of entities through a full-text search, and subsequently appends a condition containing these identifiers to the data loader. Consequently, when a DataGrid
is linked to this data loader, it will display only those records that match the full-text search criteria, combined with other filters, if any.
Search Strategies
A search strategy defines how the search term is processed. Basically it configures search request with some query.
The SearchField
and FullTextFilter
components support the following built-in search strategies:
-
anyTermAnyField
- a document matches if it contains at least one of input words in any indexed field. -
allTermsAnyField
- a document matches if it contains all input words in any field in any order. This strategy is set by default. -
allTermsSingleField
- a document matches if it has at least one field that contains all input words in any order. -
phrase
- a document matches if it has at least one field that contains all input words in the provided order.
You can set the proper strategy by using the strategy
attribute, for example:
<search:fullTextFilter dataLoader="ordersDl"
autoApply="true"
searchStrategy="anyTermAnyField"/>
To override the default strategy, add the following property to your application.properties
file:
jmix.search.default-search-strategy = allTermsSingleField
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:
-
OpenSearchSearchStrategy
- if you use OpenSearch. -
ElasticsearchSearchStrategy
- 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 you search request using provided builder according to your requirements.
@Component
public class CustomOpenSearchSearchStrategy implements OpenSearchSearchStrategy {
@Override
public String getName() {
return "CustomStrategy";
}
@Override
public void configureRequest(SearchRequest.Builder requestBuilder, SearchContext searchContext) {
//configure your request
requestBuilder.query(queryBuilder ->
queryBuilder.multiMatch(multiMatchQueryBuilder ->
multiMatchQueryBuilder.fields("*")
.query(searchContext.getSearchText())
)
);
}
}
After that, you can assign your custom strategy to the SearchField
or FullTextFilter
component using the strategy name.
Full-text Search Condition in GenericFilter Component
When the Search add-on is added to the project, a new condition appears in the Add condition dialog of the GenericFilter component:
Within the Full-text filter condition editor dialog, you can define a caption for the full-text filter and choose a search strategy. If no search strategy is selected, then the default one is used.
Subsequently, the records in the list component linked to the filter will undergo filtering based on the outcome of the full-text search.
Using Search API in Views
You can use Search API in view controllers. Let’s look at the example:
@Autowired
private EntitySearcher entitySearcher;
@Autowired
private SearchResultProcessor searchResultProcessor;
@Subscribe(id = "searchBtn", subject = "clickListener") (1)
public void onSearchBtnClick(final ClickEvent<JmixButton> event) {
SearchContext searchContext = new SearchContext("silver") (2)
.setSize(20) (3)
.setEntities("Order_"); (4)
SearchResult searchResult = entitySearcher.search(searchContext); (5)
Collection<Object> instances =
searchResultProcessor.loadEntityInstances(searchResult); (6)
// ...
}
1 | API is called from the view when clicking on a button. |
2 | Defining the search string is mandatory: here, the query will look through all fields marked for indexing that contain the "silver" string. |
3 | Adds the conditions for the query: firstly, the max amount of records in the result set. Default value is 10 . |
4 | Next, the list of entities to search within. By default, all indexed entities are included. |
5 | The EntitySearcher service is used to start searching. |
6 | SearchResultProcessor is used for fetching entities from the search result. |