Spring data 多字段排序方法

当实现一个字符查询功能时,一般都会以搜索结果的质量高低来降序显示 relevancy of each search result这也正是Solr的做法。

然而,有时也需要采用手工干预的方式来调整展示顺序。其中一个场景就是在之前文中previous part of my Spring Data Solr tutorial.提到的”常规”检索的实现

该文说明了如何使用Spring Data Solr来分类查询结果。具体就是说明如何通过修改示例应用的查询功能以使用id字段的值来降序展示查询结果。

文章可以分为三大块:

  • 第一部分讲解了如何在查询语句中设置排序条件

  • 第二部分说的是使用查询方法时如何排序查询结果

  • 第三部分告诉我们如何进行动态查询结果的排序

咱们继续往下看

petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

定义排序条件

查询语句中的排序是通过 Sort 类来实现的。常见的排序方式如下:

  • 按单个字段结果排序

  • 当按多个不同字段的排序结果相同时按多个字段组合排序

  • 当按多个不同字段的排序结果不同时按多个字段组合排序

下来看看如何创建实现上述条件的Sort对象

首先,创建一个按单字段排序的Sort对象。假设我们想按照Id字段的值来升序排列,实现代码如下:

1 new Sort(Sort.Direction.ASC, "id")
petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

其次,创建满足场景二中的Sort对象。这里假设我们使用id 和description 为查询字段并将结果以降序排列。实现代码如下:

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

最后,创建满足场景三的Sort对象。这里假设降序排列description升序排列id 字段的查询结果。实现代码如下:

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

现在知道了如何创建相应的Sort对象,再来看看如何在具体情况中的使用。

petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

查询方法结果排序

当使用查询方法时,可以按以下步骤来排序查询结果:

1. 在方法体中加入Sort参数。用来传递排序设置

2. 在服务层创建一个Sort对象,当调用查询方法时将其作为变量传递过去

下面具体看一下是如何实现的.

修改Repository接口

我们可以通过在查询方法体中添加一个变量来控制将来查询结果的排序情况。下面来看看查询方法的定义

petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

从方法名派生查询语句

如果使用了从方法名生成查询语句的策略,那需要在TodoDocumentRepositoryinterface的

findByTitleContainsOrDescriptionContains() 方法中添加Sort参数。源码如下:

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

命名查询语句

如果使用命名查询语句的策略,那需要在odoDocumentRepository 的thefindByNamedQuery() 方法中添加Sort参数。源码如下:

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

注意: 如果使用的是Spring Data Solr RC1该功能不能正常工作源于 known bug.

如此,要么使用snapshot依赖或是使用RC2版本

petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

@Query 注解

如果使用@Query注解模式,我们要在theTodoDocumentRepository 接口中的 findByQueryAnnotation() 方法中添加Sort 参数。源码如下:

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

注意: 如果使用的是Spring Data Solr RC1该功能不能正常工作源于known bug.如此,要么使用snapshot依赖或是使用RC2版本

查询方法

通过修改RepositoryIndexService 类中的thesearch() 方法实现修改查询方法体

1.       创建sortByIdDesc()方法实现以文档的id为关键字降序排列结果

2.       通过调用 TodoDocumentRepository接口中定义的查询方法获取查询结果

3.       返回查询结果集

再来看看search()方法的不同实现方式

petert
petert
翻译于 2个月前

0人顶

 翻译的不错哦!

从方法名称生成查询

当我们按照方法名称策略通过查询生成来构造我们的查询时,可以使用TodoDocumentRepository接口的findByTitleContainsOrDescriptionContains() 方法获得查询结果。

RepositoryTodoIndexService 类的相关部分源代码大致如下:

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

命名查询

当我们用命名查询构建我们的查询时,我们可以利用TodoDocumentRepository接口的findByNamedQuery()方法得到查询结果。

RepositoryTodoIndexService 相关部分的代码如下:

01 import org.springframework.data.domain.Sort;
02 import org.springframework.stereotype.Service;
03 import javax.annotation.Resource;
04 import java.util.List;
05  
06 @Service
07 public class RepositoryTodoIndexService implements TodoIndexService {
08  
09     @Resource
10     private TodoDocumentRepository repository;
11  
12     @Override
13     public List<TodoDocument> search(String searchTerm) {
14         return repository.findByNamedQuery(searchTerm, sortByIdDesc());
15     }
16  
17     private Sort sortByIdDesc() {
18         return new Sort(Sort.Direction.DESC, "id");
19     }
20     
21     //其它的方法省略
22 }
赵亮-碧海情天
赵亮-碧海情天
翻译于 2个月前

0人顶

 翻译的不错哦!

@Query 注解

当我们使用@Query注解来构建我们的查询时,我们可以使用TodoDocumentRepository接口的findByQueryAnnotation()方法来获取查询结果。

RepositoryTodoIndexService 类的相关部分如下:

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

排序动态查询的查询结果

因为动态查询 是通过 在仓储接口中添加自定义方法实现的, 所以对动态查询的结果进行排序的步骤不会影响到我们的实例应用中的Service层。

我们可以通过对我们自定义仓储接口的实现进行如下修改来排序动态查询的结果集。

  1. TodoDocumentRepositoryImpl类中添加一个 private sortByIdDesc() 方法。这个方法返回一个Sort对象,这个对象指定查询结果集以id降序排列。

  2. 修改TodoDocumentRepositoryImpl 的search()方法.使用Query 接口的addSort()方法来设置执行查询的排序选项,并且将创建的Sort对象作为参数传递给addSort()。

TodoDocumentRepositoryImpl 类的相关方法如下:

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

GoodLoser
GoodLoser
翻译于 2个月前

0人顶

 翻译的不错哦!

其它翻译版本(1)

@Query注解

当我们用@Query注解构建我们的查询时,我们可以使用TodoDocumentRepository 接口的findByQueryAnnotation()方法来获取查询结果。

RepositoryTodoIndexService类中的相关部分就像下面这样:

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

对动态查询的查询结果进行排序

由于动态查询是通过给一个repository接口添加自定义方法来创建的,对一个动态查询的结果进行排序所需要的步骤,将不会对我们示例应用中的服务层产生影响。

要给动态查询的结果进行排序,我们可以把我们自定义的repository接口的实现类做如下改变:

  1. TodoDocumentRepositoryImpl类添加一个私有的sortByIdDesc()方法。该方法返回一个Sort对象,用来指定查询结果按照id 字段进行倒序排序。

  2. 修改TodoDocumentRepositoryImpl类的search() 方法。通过使用Query接口的addSort()方法并传入一个创建好的Sort对象,来设定排序。

TodoDocumentRepositoryImpl类中的相关部分,就像下面这样:

01 import org.springframework.data.domain.Page;
02 import org.springframework.data.domain.Sort;
03 import org.springframework.data.solr.core.SolrTemplate;
04 import org.springframework.data.solr.core.query.Criteria;
05 import org.springframework.data.solr.core.query.SimpleQuery;
06 import org.springframework.stereotype.Repository;
07  
08 import javax.annotation.Resource;
09 import java.util.List;
10  
11 @Repository
12 public class TodoDocumentRepositoryImpl implements CustomTodoDocumentRepository {
13  
14     @Resource
15     private SolrTemplate solrTemplate;
16  
17     @Override
18     public List<TodoDocument> search(String searchTerm) {
19         String[] words = searchTerm.split(" ");
20  
21         Criteria conditions = createSearchConditions(words);
22         SimpleQuery search = new SimpleQuery(conditions);
23         
24         //SET SORT OPTIONS
25         search.addSort(sortByIdDesc());
26  
27         Page results = solrTemplate.queryForPage(search, TodoDocument.class);
28         return results.getContent();
29     }
30  
31     private Criteria createSearchConditions(String[] words) {
32