我们已经了解了如何配置Spring Data Solr。 我们还学习了如何向Solr索引添加新文档,如何更新现有文档的信息以及从Solr索引删除文档。 现在是时候继续前进,学习如何使用Spring Data Solr从Solr索引中搜索信息。 我们的搜索功能的要求如下:
- 搜索功能必须返回标题或描述包含给定搜索词的所有待办事项。
- 搜索必须不区分大小写。
我们可以按照以下步骤实现搜索功能:
- 创建一个查询方法。
- 使用创建的查询方法。
让我们继续研究如何使用查询方法实现搜索功能。
注意:这些博客条目提供了其他信息,有助于我们理解此博客条目中描述的概念:
创建查询方法
查询方法是
- 添加到存储库界面。
- 用于指定在调用查询方法时执行的搜索查询。
- 用于构建静态查询(具有相同数量查询参数的查询)。
我们可以通过以下技术使用Spring Data Solr创建查询方法:
- 从方法名称查询生成
- 命名查询
- @Query批注
在以下小节中将更详细地描述这些技术。
从方法名称查询生成
从方法名称生成查询是一种查询生成策略,其中从查询方法的名称解析执行的查询。
- 查询方法的名称必须以特殊的前缀开头,该前缀标识查询方法。 这些前缀是: find,findBy,get,getBy,read和readBy 。 解析执行的查询时,将从方法名称中删除此前缀。
- 属性表达式用于引用我们文档类的属性。
- 特殊关键字与属性表达式一起使用,以指定在创建的查询中使用的运算符。 在属性表达式之后,将这些关键字添加到查询方法的名称中。
- 我们可以通过在属性表达式之间添加And或Or关键字来组合属性表达式。
- 查询方法的参数计数必须等于其名称中使用的属性表达式的数量。
通过阅读以下资源,我们可以获得有关属性表达式和存储库关键字的更多信息:
我们记得,我们的搜索功能必须返回标题或描述包含给定搜索词的所有待办事项。 同样,我们的文档类具有两个在查询中使用的属性。 这些属性称为title和description 。 通过执行以下步骤,我们可以创建满足搜索功能要求的方法名称:
- 将findBy前缀添加到方法名称的开头。
- 在前缀之后添加title属性的属性表达式。
- 在属性表达式之后添加Contains关键字。
- 将Or关键字添加到方法名称。
- 在Or关键字之后添加description属性的属性表达式。
- 将Contains关键字添加到方法名称。
- 在我们的查询方法中添加两个方法参数。 第一个参数与title属性匹配,第二个参数与description属性匹配。
TodoDocumentRepository接口的源代码如下所示:
import org.springframework.data.solr.repository.SolrCrudRepository;
import java.util.List;
public interface TodoDocumentRepository extends SolrCrudRepository<TodoDocument, String> {
public List<TodoDocument> findByTitleContainsOrDescriptionContains(String title, String description);
}
注意:如果搜索词包含多个单词,则此查询方法将不起作用。
命名查询
命名查询是在单独的属性文件中声明并连接到正确查询方法的查询。 以下描述了有关用于声明命名查询的属性文件的规则:
- 属性文件的默认位置是META-INF / solr-named-queries.properties,但是我们可以使用@EnableSolrRepositories批注的namedQueriesLocation属性来配置位置。
- 使用以下公式创建每个命名查询的键: [文档类的名称]。[命名查询的名称] 。
使用以下规则,将在属性文件中配置的命名查询与我们的存储库界面的查询方法进行匹配:
- 执行命名查询的查询方法的名称必须与命名查询的名称相同。
- 如果查询方法的名称与命名查询的名称不同,则必须使用@Query注释对查询方法进行注释,并且必须使用@Query注释的name属性配置命名查询的名称 。 。
通过执行以下步骤,我们可以使用命名查询实现查询方法:
- 指定命名查询。
- 创建查询方法。
下面将更详细地描述这些步骤。
指定命名查询
通过执行以下步骤,我们可以创建一个满足查询功能要求的命名查询:
- 创建包含命名查询的属性文件。
- 使用前面描述的公式为命名查询创建一个键。 由于文档类的名称为TodoDocument ,因此命名查询的键为TodoDocument.findByNamedQuery 。
- 使用Lucene查询解析器语法创建命名查询。 因为我们的查询必须返回标题或描述包含给定搜索词的文档,所以我们的查询是: title:*?0 * OR description:*?0 * ( ?0替换为查询方法的第一个参数的值)。
META-INF / solr-named-query.properties文件的内容如下所示:
TodoDocument.findByNamedQuery=title:*?0* OR description:*?0*
创建查询方法
通过执行以下步骤,我们可以创建使用创建的命名查询的查询方法:
- 将findByNamedQuery()方法添加到TodoDocumentRepository接口。 这个方法返回TodoDocument对象的列表中,并称为SEARCHTERM一个字符串参数。
- 用@Query注释注释该方法,并将其name属性的值设置为'TodoDocument.findByNamedQuery'。 不需要此步骤,因为查询方法的名称与命名查询的名称相同,但是我想在此处演示@Query注释的用法。
TodoDocumentRepository接口的源代码如下所示:
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
import java.util.List;
public interface TodoDocumentRepository extends SolrCrudRepository<TodoDocument, String> {
@Query(name = "TodoDocument.findByNamedQuery")
public List<TodoDocument> findByNamedQuery(String searchTerm);
}
@Query注释
@Query批注可用于指定在调用查询方法时执行的查询。 通过执行以下步骤,我们可以创建满足搜索功能要求的查询方法:
- 将findByQueryAnnotation()方法添加到TodoDocumentRepository接口。 这个方法返回TodoDocument对象的列表,它有一个名为SEARCHTERM一个字符串参数。
- 用@Query注释对方法进行注释。
- 将执行的查询设置为@Query批注的值。 我们可以使用Lucene查询解析器语法创建查询。 因为我们的查询必须返回标题或描述包含给定搜索词的文档,所以正确的查询是: title:*?0 * OR description:*?0 * ( ?0替换为查询方法的第一个参数的值) 。
TodoDocumentRepository接口的源代码如下所示:
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
import java.util.List;
public interface TodoDocumentRepository extends SolrCrudRepository<TodoDocument, String> {
@Query("title:*?0* OR description:*?0*")
public List<TodoDocument> findByQueryAnnotation(String searchTerm);
}
使用创建的查询方法
我们可以按照以下步骤使用创建的查询方法:
- 在TodoIndexService接口中声明search()方法。
- 将search()方法的实现添加到RepositoryTodoIndexService类。
在以下小节中将更详细地描述这些步骤。
声明搜索方法
我们的第一步是在TodoIndexService接口中声明搜索方法。 TodoIndexService接口的相关部分如下所示:
import java.util.List;
public interface TodoIndexService {
public List<TodoDocument> search(String searchTerm);
}
实施搜索方法
我们的第二步是实现search()方法。 我们的实现非常简单。 它通过调用TodoDocumentRepository接口的正确方法来获取TodoDocument对象的列表,并返回该列表。
查询方法的名称取决于用于创建查询方法的技术。 下面描述不同的实现。
从方法名称查询生成
当我们从查询方法的名称生成查询时,我们的实现通过调用TodoDocumentRepository接口的findByTitleContainsOrDescriptionContains()方法获取TodoDocument对象的列表,并返回该列表。
RepositoryTodoIndexService类的相关部分如下所示:
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);
}
}
命名查询
如果使用命名查询,则我们的实现将通过调用TodoDocumentRepository接口的findByNamedQuery()方法获取TodoDocument对象的列表,并返回该列表。
RepositoryTodoIndexService类的相关部分如下所示:
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);
}
}
@Query注释
当我们使用@Query批注时,我们的实现通过调用TodoDocumentRepository接口的findByQueryAnnotation()方法获取TodoDocument对象的列表,并返回该列表。
RepositoryTodoIndexService类的相关部分如下所示:
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);
}
}
选择正确的查询创建技术
显而易见的问题是:
将查询方法添加到我们的Spring Data Solr存储库中的最佳方法是什么?
在为查询方法确定正确的查询创建技术时,可以使用以下准则:
- 如果创建的查询非常简单,则从方法名称生成查询通常是最佳选择。 这种方法的问题在于,用这种方法实现“复杂”查询会导致方法名称冗长而丑陋。
- 将查询保持在查询方法附近是一个好主意。 使用@Query批注的好处是,我们可以通过阅读存储库接口的源代码来查看执行的查询和查询方法。
- 如果我们想将执行的查询与存储库接口分开,则应使用命名查询。 这种方法的问题是我们必须从属性文件中检查已执行的查询,这非常麻烦。
摘要
现在,我们已经了解了如何使用Spring Data Solr创建静态查询。 这篇博客文章告诉我们两件事:
- 我们知道什么是查询方法,以及如何创建它们。
- 我们熟悉各种查询创建技术,并且知道何时使用它们。
Github上提供了演示此博客条目中描述的概念的示例应用程序。 在本教程的下一部分中,我们将学习如何将自定义功能添加到单个存储库 。
翻译自: https://www.javacodegeeks.com/2013/05/spring-data-solr-tutorial-query-methods.html