Использование поиска в UI

Визуальные компоненты

Дополнение Search предоставляет два UI-компонента: SearchField и FullTextFilter.

Эти компоненты доступны в палитре Add Component в Дизайнере экранов Jmix Studio сразу после установки дополнения в ваш проект.

Если вы не используете дизайнер экранов, объявите пространство имен search в XML-дескрипторе вашего экрана вручную:

<view xmlns="http://jmix.io/schema/flowui/view"
      xmlns:search="http://jmix.io/schema/search/ui"
      title="msg://searchView.title">

SearchField

Компонент SearchField представляет текстовое поле ввода вместе с кнопкой для выполнения поиска. Кроме того, он предоставляет опции конфигурации во время выполнения, доступные через кнопку настроек.

Вот пример использования компонента SearchField внутри экрана:

<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>

Атрибуты компонента SearchField:

  • settingsButtonVisible - показывает/скрывает кнопку настроек. Значение по умолчанию: true.

  • searchButtonVisible - показывает/скрывает кнопку поиска. Значение по умолчанию: true.

  • searchStrategy - определяет применяемую стратегию поиска. Если стратегия не указана, используется стратегия по умолчанию.

  • entities - определяет сущности для поиска. Несколько сущностей могут быть перечислены в виде последовательности, разделенной запятыми:

    <search:searchField id="searchField"
                        entities="Customer, Order_"/>

Конфигурация во время выполнения

Компонент SearchField включает кнопку настроек для динамической конфигурации. Пользователи могут динамически настраивать:

  • Стратегию поиска

  • Размер поиска (количество результатов)

  • Целевые сущности

По умолчанию searchField открывает встроенный SearchResultsView. Этот экран управляет процессом выполнения запроса к поисковому движку и отображает список результатов в контейнере навигации или в новом диалоговом окне, в зависимости от атрибута openMode компонента searchField.

Если вы хотите изменить эту функциональность, вы можете настроить SearchCompletedHandler следующим образом:

@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();
}

Альтернативно, вы можете использовать метод setSearchCompletedHandler() компонента.

FullTextFilter

Компонент FullTextFilter функционирует аналогично компоненту propertyFilter.

Вот пример использования fullTextFilter в экране:

<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>

Атрибуты компонента FullTextFilter:

  • dataLoader определяет DataLoader, к которому применяется фильтр.

  • searchStrategy определяет используемую стратегию поиска. Если не определена явно, используется стратегия по умолчанию.

  • autoApply - при значении true компонент FullTextFilter автоматически применяется к DataLoader при изменении своего значения.

FullTextFilter работает следующим образом: он находит идентификаторы сущностей через полнотекстовый поиск и затем добавляет условие, содержащее эти идентификаторы, в загрузчик данных. Следовательно, когда DataGrid связан с этим загрузчиком данных, он будет отображать только те записи, которые соответствуют критериям полнотекстового поиска, в сочетании с другими фильтрами, если они есть.

Стратегии поиска

Стратегия поиска определяет, как обрабатывается поисковый термин. По сути, она конфигурирует поисковый запрос с определенным запросом.

Компоненты SearchField и FullTextFilter поддерживают следующие встроенные стратегии поиска:

  • startsWith

    Эта стратегия доступна только когда @ExtendedSearch включен хотя бы для одного определения индекса.

    Выполняет поиск на основе префикса, используя предварительно индексированные подполя Edge N-Gram:

    • Генерирует все префиксы от jmix.search.min-prefix-length (по умолчанию: 3) до jmix.search.max-prefix-length (по умолчанию: 8).

    • Обеспечивает значительно более высокую производительность по сравнению с запросами по шаблону (wildcard).

    • Когда введенный термин превышает максимальную длину префикса, выполняется резервный запрос по шаблону, если jmix.search.wildcard-prefix-query-enabled = true (значение по умолчанию).

      Для терминов короче, чем jmix.search.min-prefix-length, поиск всегда возвращает пустой результат.
  • phrase

    Выполняет поиск точной фразы:

    • Документы должны содержать все поисковые термины в точном порядке в рамках одного поля.

    • Эквивалентно традиционному фразовому запросу в поисковых системах.

    • Идеально подходит для поиска по именам, названиям или точным формулировкам.

  • anyTermAnyField

    Выполняет дизъюнктивное сопоставление терминов по всем полям:

    • Возвращаются документы, соответствующие любому из введенных терминов в любом индексированном поле.

    • Термины комбинируются с логикой ИЛИ.

    • Стратегия по умолчанию для обратной совместимости.

    Эта стратегия установлена по умолчанию.

allTermsAnyField и allTermsSingleField объявлены устаревшими и скрыты из пользовательского интерфейса, но при необходимости могут быть повторно реализованы.

Вы можете установить нужную стратегию, используя атрибут searchStrategy, например:

<search:fullTextFilter dataLoader="ordersDl"
                       autoApply="true"
                       searchStrategy="anyTermAnyField"/>

Чтобы переопределить стратегию по умолчанию, добавьте следующее свойство в ваш файл application.properties:

jmix.search.default-search-strategy = phrase

Пользовательские стратегии поиска

Дополнительно вы можете создать пользовательскую стратегию поиска. Для этой цели вам нужно создать новый Spring-бин, реализующий один из специфичных для платформы интерфейсов:

  • OpenSearchSearchStrategy - если вы используете OpenSearch.

  • ElasticsearchSearchStrategy - если вы используете Elasticsearch.

Затем вам нужно реализовать 2 метода:

  • String getName() - должен возвращать уникальное имя стратегии.

  • void configureRequest(SearchRequest.Builder requestBuilder, SearchContext searchContext) - настройте ваш поисковый запрос, используя предоставленный builder, в соответствии с вашими требованиями.

@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())
                )
        );
    }
}

После этого вы можете назначить вашу пользовательскую стратегию компоненту SearchField или FullTextFilter, используя имя стратегии.

Условие полнотекстового поиска в компоненте GenericFilter

Когда дополнение Search добавлено в проект, в диалоговом окне Add condition компонента GenericFilter появляется новое условие:

add condition

В диалоговом окне Full-text filter condition editor вы можете определить надпись для полнотекстового фильтра и выбрать стратегию поиска. Если стратегия поиска не выбрана, то используется стратегия по умолчанию.

condition editor

Впоследствии записи в компоненте списка, связанном с фильтром, будут фильтроваться на основе результата полнотекстового поиска.

Использование Search API в экранах

Вы можете использовать Search API в контроллерах экранов. Рассмотрим пример:

@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 вызывается из экрана при нажатии на кнопку.
2 Определение поисковой строки обязательно: здесь запрос будет искать по всем полям, помеченным для индексации, которые содержат строку "silver".
3 Добавляет условия для запроса: во-первых, максимальное количество записей в результирующем наборе. Значение по умолчанию - 10.
4 Далее, список сущностей, в которых осуществляется поиск. По умолчанию включены все индексированные сущности.
5 Сервис EntitySearcher используется для начала поиска.
6 SearchResultProcessor используется для извлечения сущностей из результата поиска.