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 the DataLoader to be filtered.

  • searchStrategy determines the search strategy to be employed. If not explicitly defined, a default strategy is utilized.

  • autoApply - when set to true, the FullTextFilter component automatically applies itself to the DataLoader 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:

add condition

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.

condition editor

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.