Статьи

Руководство по Spring Data Solr: сортировка

Когда мы реализуем функцию поиска по слову, мы обычно хотим отсортировать результаты поиска в порядке убывания, используя релевантность каждого результата поиска . Это также поведение по умолчанию Solr.

Однако бывают ситуации, когда имеет смысл задавать порядок сортировки вручную. Одной из таких ситуаций является реализация «обычной» функции поиска, которая обсуждалась в предыдущей части моего руководства по Spring Data Solr .

В этом блоге описывается, как мы можем сортировать результаты наших запросов с помощью Spring Data Solr. Чтобы быть более конкретным, мы должны изменить функцию поиска нашего примера приложения, чтобы отсортировать результаты поиска в порядке убывания, используя значение поля id .

Этот блог разделен на три раздела:

  • В первом разделе описывается, как мы можем указать параметры сортировки, используемые в наших запросах.
  • Во втором разделе описывается, как мы можем сортировать результаты наших запросов при построении наших запросов с использованием методов запросов.
  • Третий раздел учит нас сортировать результаты динамических запросов.

Давайте начнем.

Примечание. Эти посты в блоге предоставляют дополнительную информацию, которая помогает нам понять концепции, описанные в этом посте:

Указание параметров сортировки запроса

Параметры сортировки запроса указываются с помощью класса Sort . Типичные требования для сортировки результатов запроса приведены в следующем:

  • Сортируйте результаты запроса, используя значение одного поля.
  • Сортируйте результаты запроса, используя значения нескольких полей, если порядок сортировки разных полей одинаков.
  • Сортируйте результаты запроса, используя значения нескольких полей, если порядок сортировки разных полей не одинаков.

Давайте посмотрим, как мы можем создать объект Sort, который удовлетворяет заданным требованиям.

Во-первых, мы должны создать объект Sort, который указывает, что результаты запроса сортируются с использованием одного поля. Предположим, что мы хотим отсортировать результаты запроса в порядке возрастания, используя поле id . Мы можем создать объект Sort , используя следующий код:

1
new Sort(Sort.Direction.ASC, "id")

Во-вторых, мы должны создать объект Sort, в котором говорится, что результаты запроса сортируются с использованием значений нескольких полей, когда порядок сортировки разных полей одинаков. Предположим, что мы должны отсортировать результаты запроса в порядке убывания, используя поля id и description . Мы можем создать объект Sort , используя следующий код:

1
new Sort(Sort.Direction.DESC, "id", "description")

В-третьих, мы хотим отсортировать результаты запроса, используя значения нескольких полей, когда порядок сортировки разных полей не одинаков. Предположим, что мы хотим отсортировать результаты запроса в порядке убывания, используя поле описания, и в порядке возрастания, используя поле id . Мы можем создать объект Sort , используя следующий код:

1
new Sort(Sort.Direction.DESC, "description").and(new Sort(Sort.Direction.ASC, "id"))

Теперь мы знаем, как мы можем создавать новые объекты сортировки . Давайте двигаться дальше и применять эту теорию на практике.

Сортировка результатов запроса методов запроса

Когда мы строим наши запросы, используя методы запросов, мы можем отсортировать результаты запроса, выполнив следующие действия:

  1. Добавьте новый параметр сортировки в метод запроса. Этот параметр метода указывает используемые параметры сортировки.
  2. Создайте новый объект Sort на уровне сервиса и передайте его в качестве параметра метода при вызове метода запроса.

Давайте двигаться дальше и узнаем, как это делается.

Модификация интерфейса репозитория

Мы можем отсортировать результаты нашего запроса, добавив новый параметр Sort в наш метод запроса. Этот параметр метода указывает параметры сортировки выполненного запроса. Давайте продолжим и посмотрим на объявления наших методов запросов.

Генерация запроса из имени метода

Когда выполненный запрос создается с использованием генерации запроса из стратегии с именем метода, нам необходимо добавить параметр Sort в метод findByTitleContainsOrDescriptionContains () интерфейса TodoDocumentRepository . Исходный код нашего интерфейса репозитория выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
 
import java.util.List;
 
public interface TodoDocumentRepository extends PartialUpdateRepository, SolrCrudRepository<TodoDocument, String> {
 
    public List<TodoDocument> findByTitleContainsOrDescriptionContains(String title, String description, Sort sort);
}

Именованные Запросы

Когда выполненный запрос создается с использованием именованных запросов, мы должны добавить параметр Sort в метод findByNamedQuery () интерфейса TodoDocumentRepository . Исходный код нашего интерфейса репозитория выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
 
import java.util.List;
 
public interface TodoDocumentRepository extends PartialUpdateRepository, SolrCrudRepository<TodoDocument, String> {
 
    @Query(name = "TodoDocument.findByNamedQuery")
    public List<TodoDocument> findByNamedQuery(String searchTerm, Sort sort);
}

Примечание. Этот подход не работает, если мы используем Spring Data Solr RC1 из-за известной ошибки . Мы должны либо использовать зависимость снимка сборки, либо дождаться выпуска RC2.

Аннотация @Query

Когда выполненный запрос создается с использованием аннотации @Query , мы должны добавить параметр Sort в метод findByQueryAnnotation () интерфейса TodoDocumentRepository . Исходный код нашего интерфейса репозитория выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
 
import java.util.List;
 
public interface TodoDocumentRepository extends PartialUpdateRepository, SolrCrudRepository<TodoDocument, String> {
 
    @Query("title:*?0* OR description:*?0*")
    public List<TodoDocument> findByQueryAnnotation(String searchTerm, Sort sort);
}

Примечание. Этот подход не работает, если мы используем Spring Data Solr RC1 из-за известной ошибки . Мы должны либо использовать зависимость снимка сборки, либо дождаться выпуска RC2.

Использование метода запроса

Мы можем использовать модифицированный метод запроса, внеся следующие изменения в метод search () класса RepositoryIndexService :

  1. Создайте закрытый метод sortByIdDesc (), который указывает, что результаты запроса сортируются в порядке убывания с использованием идентификатора документа.
  2. Получите отсортированные результаты запроса, вызвав метод запроса, объявленный в интерфейсе TodoDocumentRepository .
  3. Вернуть результаты запроса.

Давайте продолжим и посмотрим на различные реализации метода search () .

Генерация запроса из имени метода

Когда мы строим наши запросы, используя генерацию запросов из стратегии имени метода, мы можем получить результаты запроса, используя метод findByTitleContainsOrDescriptionContains () интерфейса TodoDocumentRepository .

Исходный код соответствующей части класса RepositoryTodoIndexService выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
 
@Service
public class RepositoryTodoIndexService implements TodoIndexService {
 
    @Resource
    private TodoDocumentRepository repository;
 
    @Override
    public List<TodoDocument> search(String searchTerm) {
        return repository.findByTitleContainsOrDescriptionContains(searchTerm, searchTerm, sortByIdDesc());
    }
 
    private Sort sortByIdDesc() {
        return new Sort(Sort.Direction.DESC, "id");
    }
    
    //Other methods are omitted
}

Именованные Запросы

Когда мы строим наши запросы, используя именованные запросы, мы можем получить результаты запроса, используя метод findByNamedQuery () интерфейса TodoDocumentRepository .

Соответствующая часть RepositoryTodoIndexService выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
 
@Service
public class RepositoryTodoIndexService implements TodoIndexService {
 
    @Resource
    private TodoDocumentRepository repository;
 
    @Override
    public List<TodoDocument> search(String searchTerm) {
        return repository.findByNamedQuery(searchTerm, sortByIdDesc());
    }
 
    private Sort sortByIdDesc() {
        return new Sort(Sort.Direction.DESC, "id");
    }
    
    //Other methods are omitted
}

Аннотация @Query

Когда мы создаем наши запросы с помощью аннотации @Query , мы можем получить результаты запроса с помощью метода findByQueryAnnotation () интерфейса TodoDocumentRepository .

Соответствующая часть класса RepositoryTodoIndexService выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
 
@Service
public class RepositoryTodoIndexService implements TodoIndexService {
 
    @Resource
    private TodoDocumentRepository repository;
 
    @Override
    public List<TodoDocument> search(String searchTerm) {
        return repository.findByQueryAnnotation(searchTerm, sortByIdDesc());
    }
 
    private Sort sortByIdDesc() {
        return new Sort(Sort.Direction.DESC, "id");
    }
    
    //Other methods are omitted
}

Сортировка результатов запросов динамических запросов

Поскольку динамические запросы создаются путем добавления пользовательского метода к интерфейсу репозитория , шаги, необходимые для сортировки результатов запроса динамического запроса, не влияют на уровень обслуживания нашего примера приложения.

Мы можем отсортировать результаты динамических запросов, внеся следующие изменения в реализацию нашего пользовательского интерфейса репозитория:

  1. Добавьте приватный метод sortByIdDesc () в класс TodoDocumentRepositoryImpl . Этот метод возвращает объект Sort, который указывает, что результаты запроса сортируются в порядке убывания с использованием идентификатора документа.
  2. Измените метод search () класса TodoDocumentRepositoryImpl . Установите параметры сортировки для выполненного запроса, используя метод addSort () интерфейса Query, и передайте созданный объект Sort в качестве параметра метода.

Соответствующая часть класса TodoDocumentRepositoryImpl выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.Criteria;
import org.springframework.data.solr.core.query.SimpleQuery;
import org.springframework.stereotype.Repository;
 
import javax.annotation.Resource;
import java.util.List;
 
@Repository
public class TodoDocumentRepositoryImpl implements CustomTodoDocumentRepository {
 
    @Resource
    private SolrTemplate solrTemplate;
 
    @Override
    public List<TodoDocument> search(String searchTerm) {
        String[] words = searchTerm.split(" ");
 
        Criteria conditions = createSearchConditions(words);
        SimpleQuery search = new SimpleQuery(conditions);
        
        //SET SORT OPTIONS
        search.addSort(sortByIdDesc());
 
        Page results = solrTemplate.queryForPage(search, TodoDocument.class);
        return results.getContent();
    }
 
    private Criteria createSearchConditions(String[] words) {
        Criteria conditions = null;
 
        for (String word: words) {
            if (conditions == null) {
                conditions = new Criteria("id").contains(word)
                        .or(new Criteria("description").contains(word));
            }
            else {
                conditions = conditions.or(new Criteria("id").contains(word))
                        .or(new Criteria("description").contains(word));
            }
        }
 
        return conditions;
    }
 
    private Sort sortByIdDesc() {
        return new Sort(Sort.Direction.DESC, "id");
    }
 
    //Other methods are omitted
}

Резюме

Теперь мы узнали, как сортировать результаты запросов с помощью Spring Data Solr. Этот урок научил нас трем вещам:

  • Мы знаем, что можем указать используемые параметры сортировки с помощью класса Sort .
  • Мы узнали, что можем отсортировать результат запроса методов запроса, добавив новый параметр метода в метод запроса.
  • Мы узнали, что мы можем установить параметры сортировки для динамического запроса, используя метод addSort () интерфейса Query .

Следующая часть моего учебника Spring Data Solr описывает, как мы можем разбить на страницы результаты наших запросов .

PS Примеры приложений этого блога доступны на Github ( методы запросов и динамические запросы ).