内容简介:接下来进入solr CURD的第四篇,查询的使用姿势介绍,本文将主要包括以下知识点在介绍demo之前,需要先安装solr环境,搭建SpringBoot项目工程,具体的环境搭建过程不细说,推荐参考文档在
接下来进入solr CURD的第四篇,查询的使用姿势介绍,本文将主要包括以下知识点
- 基本的查询操作
- fq查询
- fl指定字段查询
- 比较/范围
- 排序
- 分页
- 分组
I. 配置
在介绍demo之前,需要先安装solr环境,搭建SpringBoot项目工程,具体的环境搭建过程不细说,推荐参考文档
在 application.yml 配置文件中红,指定solr的域名
spring:
data:
solr:
host: http://127.0.0.1:8983/solr
然后在solr中,写入一些数据,供我们查询使用,可以通过控制台的方式写入,也可以通过 190526-SpringBoot高级篇搜索Solr之文档新增与修改使用姿势 这篇文档的case添加
初始化solr文档内容如下
{
"id":"1",
"content_id":1,
"title":"一灰灰blog",
"content":"这是一灰灰blog的内容",
"type":1,
"create_at":1578912072,
"publish_at":1578912072,
"_version_":1655609540674060288},
{
"id":"2",
"content_id":2,
"title":"一灰灰",
"content":"这是一灰灰的内容",
"type":1,
"create_at":1578912072,
"publish_at":1578912072,
"_version_":1655609550229733376},
{
"id":"3",
"content_id":3,
"title":"solrTemplate 修改之后!!!",
"create_at":1578993153,
"publish_at":1578993153,
"type":0,
"_version_":1655694325261008896},
{
"id":"4",
"content_id":4,
"type":1,
"create_at":0,
"publish_at":0,
"_version_":1655694325422489600},
{
"id":"5",
"content_id":5,
"title":"addBatchByBean - 1",
"content":"新增一个测试文档",
"type":1,
"create_at":1578993153,
"publish_at":1578993153,
"_version_":1655694325129936896},
{
"id":"6",
"content_id":6,
"title":"addBatchByBean - 2",
"content":"新增又一个测试文档",
"type":1,
"create_at":1578993153,
"publish_at":1578993153,
"_version_":1655694325136228352
}
II. 查询
solr文档对应的POJO如下,(注意solr中的主键id为string类型,下面定义中用的是Integer,推荐与solr的数据类型保持一致)
@Data
public class DocDO implements Serializable {
private static final long serialVersionUID = 7245059137561820707L;
@Id
@Field("id")
private Integer id;
@Field("content_id")
private Integer contentId;
@Field("title")
private String title;
@Field("content")
private String content;
@Field("type")
private Integer type;
@Field("create_at")
private Long createAt;
@Field("publish_at")
private Long publishAt;
}
1. 主键查询
支持单个查询和批量查询,三个参数,第一个为需要查询的Collection, 第二个为id/id集合,第三个为返回的数据类型
private void queryById() {
DocDO ans = solrTemplate.getById("yhh", 1, DocDO.class).get();
System.out.println("queryById: " + ans);
Collection<DocDO> list = solrTemplate.getByIds("yhh", Arrays.asList(1, 2), DocDO.class);
System.out.println("queryByIds: " + list);
}
输出结果如下
queryById: DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072) queryByIds: [DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072)]
2. 简单查询
比如最简单的根据某个字段进行查询
Query query = new SimpleQuery("title:一灰灰");
Page<DocDO> ans = solrTemplate.query("yhh", query, DocDO.class);
System.out.println("simpleQuery : " + ans.getContent());
直接在SimpleQuery中指定查询条件,上面的case表示查询title为 一灰灰 的文档
输出结果如下:
simpleQuery : [DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072)]
简单的查询使用上面的姿势ok,当然就是阅读起来不太优雅;推荐另外一种基于 Criteria 的查询条件构建方式
- 如果看过之前的 mongodb 系列教程,可以看到monodb的查询条件也用到了Criteria来拼装,但是请注意这两个并不是一个东西
query = new SimpleQuery();
// 查询内容中包含一灰灰的文档
query.addCriteria(new Criteria("content").contains("一灰灰"));
ans = solrTemplate.query("yhh", query, DocDO.class);
System.out.println("simpleQuery : " + ans.getContent());
输出结果如下
simpleQuery : [DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072)]
Criteria 可以构建复杂的且阅读友好的查询条件,后面会有具体的演示,这里给出一个多条件查询的case
// 多个查询条件
query = new SimpleQuery();
query.addCriteria(Criteria.where("title").contains("一灰灰").and("content_id").lessThan(2));
ans = solrTemplate.query("yhh", query, DocDO.class);
System.out.println("multiQuery: " + ans.getContent());
输出结果如下,在上面的基础上,捞出了contentId小于2的记录
multiQuery: [DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072)]
3. fq查询
fq 主要用来快速过滤,配合query进行操作,主要是借助 org.springframework.data.solr.core.query.Query#addFilterQuery 来添加fq条件
// fq查询
query = new SimpleQuery("content: *一灰灰*");
query.addFilterQuery(FilterQuery.filter(Criteria.where("title").contains("blog")));
ans = solrTemplate.query("yhh", query, DocDO.class);
System.out.println("simpleQueryAndFilter: " + ans.getContent());
输出结果如:
simpleQueryAndFilter: [DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072)]
4. fl指定查询字段
当我们只关注solr文档中的部分字段时,可以考虑指定fl,只获取所需的字段;通过 org.springframework.data.solr.core.query.SimpleQuery#addProjectionOnFields(java.lang.String...) 来指定需要返回的字段名
/**
* 查询指定的字段
*/
private void querySpecialFiled() {
SimpleQuery query = new SimpleQuery();
query.addCriteria(Criteria.where("content_id").lessThanEqual(2));
// fl 查询
query.addProjectionOnFields("id", "title", "content");
List<DocDO> ans = solrTemplate.query("yhh", query, DocDO.class).getContent();
System.out.println("querySpecialField: " + ans);
}
输出结果如下
querySpecialField: [DocDO(id=1, contentId=null, title=一灰灰blog, content=这是一灰灰blog的内容, type=null, createAt=null, publishAt=null), DocDO(id=2, contentId=null, title=一灰灰, content=这是一灰灰的内容, type=null, createAt=null, publishAt=null)]
请注意,我们指定了只需要返回 id , title , content ,所以返回的DO中其他的成员为null
5. 范围查询
针对数字类型,支持范围查询,比如上面给出 Criteria.where("content_id").lessThanEqual(2) ,表示查询 content_id 小于2的记录,下面给出一个between的查询
/**
* 范围查询
*/
private void queryRange() {
Query query = new SimpleQuery();
query.addCriteria(Criteria.where("content_id").between(1, 3));
query.addSort(Sort.by("content_id").ascending());
List<DocDO> ans = solrTemplate.query("yhh", query, DocDO.class).getContent();
System.out.println("queryRange: " + ans);
}
输出结果如下,请注意between查询,左右都是闭区间
queryRange: [DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=3, contentId=3, title=solrTemplate 修改之后!!!, content=null, type=0, createAt=1578997659, publishAt=1578997659)]
如果不想要闭区间,可以用 between 的重载方法
query = new SimpleQuery();
// 两个false,分表表示不包含下界 上界
query.addCriteria(Criteria.where("content_id").between(1, 3, false, false));
query.addSort(Sort.by("content_id").ascending());
ans = solrTemplate.query("yhh", query, DocDO.class).getContent();
System.out.println("queryRange: " + ans);
输出结果如
queryRange: [DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072)]
6. 排序
上面的case中,已经用到了排序,主要是 Sort 来指定排序字段以及 排序 的方式;因为id在solr中实际上是字符串格式,所以如果用id进行排序时,实际上是根据字符串的排序规则来的(虽然我们的POJO中id为int类型)
/**
* 查询并排序
*/
private void queryAndSort() {
// 排序
Query query = new SimpleQuery();
query.addCriteria(new Criteria("content").contains("一灰灰"));
// 倒排
query.addSort(Sort.by("content_id").descending());
Page<DocDO> ans = solrTemplate.query("yhh", query, DocDO.class);
System.out.println("queryAndSort: " + ans.getContent());
}
输出结果如下
queryAndSort: [DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072)]
7. 分页查询
分页查询比较常见,特别是当数据量比较大时,请一定记得,添加分页条件
一个查询case如下,查询所有的数据,并制定了分页条件,查询第二条和第三条数据(计数从0开始)
/**
* 分页
*/
private void queryPageSize() {
Query query = new SimpleQuery("*:*");
query.addSort(Sort.by("content_id").ascending());
// 指定偏移量,从0开始
query.setOffset(2L);
// 查询的size数量
query.setRows(2);
Page<DocDO> ans = solrTemplate.queryForPage("yhh", query, DocDO.class);
// 文档数量
long totalDocNum = ans.getTotalElements();
List<DocDO> docList = ans.getContent();
System.out.println("queryPageSize: totalDocNum=" + totalDocNum + " docList=" + docList);
}
在返回结果中,查了返回查询的文档之外,还会给出满足条件的文档数量,可以通过 Page#getTotalElements 获取,
上面case输出结果如下
queryPageSize: totalDocNum=6 docList=[DocDO(id=3, contentId=3, title=solrTemplate 修改之后!!!, content=null, type=0, createAt=1578997946, publishAt=1578997946), DocDO(id=4, contentId=4, title=null, content=null, type=1, createAt=0, publishAt=0)]
8. 分组查询
分组和前面的查询有一点区别,主要在于结果的处理,以及分组参数必须指定分页信息
/**
* 分组查询
*/
private void queryGroup() {
Query query = new SimpleQuery("*:*");
// 请注意,分组查询,必须指定 offset/limit, 否则会抛异常,Pageable must not be null!
GroupOptions groupOptions = new GroupOptions().addGroupByField("type").setOffset(0).setLimit(10);
query.setGroupOptions(groupOptions);
GroupPage<DocDO> ans = solrTemplate.queryForGroupPage("yhh", query, DocDO.class);
GroupResult<DocDO> groupResult = ans.getGroupResult("type");
Page<GroupEntry<DocDO>> entries = groupResult.getGroupEntries();
System.out.println("============ query for group ============ ");
for (GroupEntry<DocDO> sub : entries) {
// type 的具体值
String groupValue = sub.getGroupValue();
Page<DocDO> contentList = sub.getResult();
System.out.println("queryGroup v=" + groupValue + " content=" + contentList.getContent());
}
System.out.println("============ query for group ============ ");
}
上面的case虽然比较简单,但是有几点需要注意, 特别是返回结果的获取,包装层级有点深
- GroupOptions:
- 必须指定offset/limit,当两个条件都没有时会抛异常
- 只指定offset时,limit默认为1
- 只指定limit时,offset默认为0
- 结果处理
GroupPage#getGroupResult(field) GroupResult#getGroupEntries
输出结果如下
============ query for group ============ queryGroup v=1 content=[DocDO(id=1, contentId=1, title=一灰灰blog, content=这是一灰灰blog的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=2, contentId=2, title=一灰灰, content=这是一灰灰的内容, type=1, createAt=1578912072, publishAt=1578912072), DocDO(id=5, contentId=5, title=addBatchByBean - 1, content=新增一个测试文档, type=1, createAt=1578997946, publishAt=1578997946), DocDO(id=6, contentId=6, title=addBatchByBean - 2, content=新增又一个测试文档, type=1, createAt=1578997946, publishAt=1578997946), DocDO(id=4, contentId=4, title=null, content=null, type=1, createAt=0, publishAt=0)] queryGroup v=0 content=[DocDO(id=3, contentId=3, title=solrTemplate 修改之后!!!, content=null, type=0, createAt=1578997946, publishAt=1578997946)] ============ query for group ============
III. 其他
0. 系列博文&工程源码
系列博文
- 200114-SpringBoot系列教程Solr之文档删除
- 190526-SpringBoot高级篇搜索Solr之文档新增与修改使用姿势
- 190510-SpringBoot高级篇搜索之Solr环境搭建与简单测试
工程源码
- 工程: https://github.com/liuyueyi/spring-boot-demo
- 源码: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/140-search-solr
1. 一灰灰Blog
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
- 一灰灰Blog个人博客 https://blog.hhui.top
- 一灰灰Blog-Spring专题博客 http://spring.hhui.top
打赏 如果觉得我的文章对您有帮助,请随意打赏。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Book of CSS3
Peter Gasston / No Starch Press / 2011-5-13 / USD 34.95
CSS3 is the technology behind most of the eye-catching visuals on the Web today, but the official documentation can be dry and hard to follow. Luckily, The Book of CSS3 distills the heady technical la......一起来看看 《The Book of CSS3》 这本书的介绍吧!