当我们实现单词搜索功能时,我们通常希望通过使用每个搜索结果的相关性以降序对搜索结果进行排序。 这也是Solr的默认行为。
但是,在某些情况下,有必要手动指定排序顺序。 一种此类情况是“常规”搜索功能的实现,该功能已在我的Spring Data Solr教程的上一部分中进行了讨论。
这篇博客文章描述了如何使用Spring Data Solr对查询结果进行排序。 更具体地说,我们必须修改示例应用程序的搜索功能,以通过使用id字段的值将搜索结果降序排列。
此博客文章分为三个部分:
- 第一部分描述了如何指定查询中使用的排序选项。
- 第二部分描述了在使用查询方法构建查询时如何对查询结果进行排序。
- 第三部分教我们如何对动态查询的查询结果进行排序。
让我们开始吧。
注意:这些博客文章提供了其他信息,可帮助我们理解此博客文章中描述的概念:
- 使用Maven运行Solr
- Spring Data Solr教程:Solr简介
- Spring Data Solr教程:配置
- Spring Data Solr教程CRUD(几乎)
- Spring Data Solr教程:将自定义方法添加到单个存储库
- Spring Data Solr教程:动态查询
指定查询的排序选项
查询的排序选项是使用Sort类指定的。 下面给出了对查询结果进行排序的典型要求:
- 通过使用单个字段的值对查询结果进行排序。
- 当不同字段的排序顺序相同时,通过使用多个字段的值对查询结果进行排序。
- 当不同字段的排序顺序不同时,通过使用多个字段的值对查询结果进行排序。
让我们看一下如何创建一个满足给定要求的Sort对象。
首先,我们必须创建一个Sort对象,该对象指定使用单个字段对查询结果进行排序。 假设我们要使用id字段按升序对查询结果进行排序。 我们可以使用以下代码创建Sort对象:
new Sort(Sort.Direction.ASC, "id")
其次,我们必须创建一个Sort对象,该对象声明当不同字段的排序顺序相同时,使用多个字段的值对查询结果进行排序。 假设我们必须使用id和description字段对查询结果进行降序排序。 我们可以使用以下代码创建Sort对象:
new Sort(Sort.Direction.DESC, "id", "description")
第三,当不同字段的排序顺序不同时,我们想使用多个字段的值对查询结果进行排序。 假设我们要使用描述字段以降序对查询结果进行排序,并使用id字段以升序对查询结果进行排序。 我们可以使用以下代码创建Sort对象:
new Sort(Sort.Direction.DESC, "description").and(new Sort(Sort.Direction.ASC, "id"))
现在我们知道如何创建新的Sort对象。 让我们继续实践该理论。
对查询方法的查询结果进行排序
使用查询方法构建查询时,可以按照以下步骤对查询结果进行排序:
- 将新的Sort参数添加到查询方法。 此方法参数指定使用的排序选项。
- 在服务层中创建一个新的Sort对象,并在调用查询方法时将其作为方法参数传递。
让我们继续前进,找出实现方法。
修改存储库界面
通过将新的Sort参数添加到我们的查询方法中,我们可以对查询的查询结果进行排序 。 此方法参数指定执行的查询的排序选项。 让我们继续看一下查询方法的声明。
从方法名称查询生成
通过使用从方法名策略生成查询来创建执行的查询时,我们必须在TodoDocumentRepository接口的findByTitleContainsOrDescriptionContains()方法中添加一个Sort参数。 我们的存储库界面的源代码如下所示:
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);
}
命名查询
当使用命名查询创建执行的查询时,我们必须在TodoDocumentRepository接口的findByNamedQuery()方法中添加一个Sort参数。 我们的存储库界面的源代码如下所示:
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);
}
注意:如果由于已知的bug,我们在使用Spring Data Solr RC1时,这种方法不起作用。 我们要么使用构建快照依赖项,要么等待RC2的发布。
@Query注释
使用@Query批注创建执行的查询时,我们必须在TodoDocumentRepository接口的findByQueryAnnotation()方法中添加一个Sort参数。 我们的存储库界面的源代码如下所示:
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);
}
注意:如果由于已知的bug,我们在使用Spring Data Solr RC1时,这种方法不起作用。 我们要么使用构建快照依赖项,要么等待RC2的发布。
使用查询方法
我们可以通过对RepositoryIndexService类的search()方法进行以下更改来使用修改后的查询方法:
- 创建一个私有的sortByIdDesc()方法,该方法指定查询结果通过使用文档的ID降序排列。
- 通过调用TodoDocumentRepository接口中声明的查询方法来获取排序的查询结果。
- 返回查询结果。
让我们继续来看一下search()方法的不同实现。
从方法名称查询生成
通过使用从方法名称策略生成查询来构建查询时,可以使用TodoDocumentRepository接口的findByTitleContainsOrDescriptionContains()方法获取查询结果。
RepositoryTodoIndexService类的相关部分的源代码如下所示:
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 {@Resourceprivate TodoDocumentRepository repository;@Overridepublic 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
}
命名查询
使用命名查询构建查询时,可以使用TodoDocumentRepository接口的findByNamedQuery()方法获取查询结果。
RepositoryTodoIndexService的相关部分如下所示:
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 {@Resourceprivate TodoDocumentRepository repository;@Overridepublic 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批注构建查询时,可以使用TodoDocumentRepository接口的findByQueryAnnotation()方法获取查询结果。
RepositoryTodoIndexService类的相关部分如下所示:
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 {@Resourceprivate TodoDocumentRepository repository;@Overridepublic List<TodoDocument> search(String searchTerm) {return repository.findByQueryAnnotation(searchTerm, sortByIdDesc());}private Sort sortByIdDesc() {return new Sort(Sort.Direction.DESC, "id");}//Other methods are omitted
}
对动态查询的查询结果进行排序
由于动态查询是通过向存储库接口添加自定义方法而创建的,因此对动态查询的查询结果进行排序所需的步骤对示例应用程序的服务层无效。
通过对自定义存储库接口的实现进行以下更改,我们可以对动态查询的查询结果进行排序:
- 向TodoDocumentRepositoryImpl类添加一个私有的sortByIdDesc()方法。 此方法返回一个Sort对象,该对象指定通过使用文档的ID对查询结果进行降序排序。
- 修改TodoDocumentRepositoryImpl类的search()方法。 使用Query接口的addSort()方法将排序选项设置为执行的查询,并将创建的Sort对象作为方法参数传递。
TodoDocumentRepositoryImpl类的相关部分如下所示:
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 {@Resourceprivate SolrTemplate solrTemplate;@Overridepublic List<TodoDocument> search(String searchTerm) {String[] words = searchTerm.split(" ");Criteria conditions = createSearchConditions(words);SimpleQuery search = new SimpleQuery(conditions);//SET SORT OPTIONSsearch.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类来指定使用的排序选项。
- 我们了解到,可以通过向查询方法添加新的方法参数来对查询方法的查询结果进行排序。
- 我们了解到,可以使用Query接口的addSort()方法将排序选项设置为动态查询。
我的Spring Data Solr教程的下一部分描述了如何对查询的查询结果进行分页 。
PS:此博客文章的示例应用程序可在Github上获得( 查询方法和动态查询 )。
翻译自: https://www.javacodegeeks.com/2013/05/spring-data-solr-tutorial-sorting.html