有时我们可能需要将查询到的结果按某个字段分组后列出,这时就必须用到solr的分组查询功能,即Grouping。
举例如下:
现有一个产品表,每个产品包含品牌(brand_name)和品名(product_name)字段,我们要根据关键字,查找至少在这两个字段之一包含这个关键字的产品数据,按照产品品牌分组列出。
如果查询空调,结果包含两个品牌A空调,两个品牌B空调,那么品牌A为一组,品牌B为一组。
下面首先设置查询条件
SolrQuery query = new SolrQuery();
//设置查询字段及相应的关键字
query
.setQuery("product_name:空调 OR brand_name:空调")
//这里设置返回的字段
.set(CommonParams.FL,
"id",
"brand_name",
"product_name",
"credit_score")
//开启分组功能
.set(GroupParams.GROUP,true)
//按照品牌分组
.set(GroupParams.GROUP_FIELD,"brand_name")
//设置每个分组里从第几条数据开始返回,用于组内分页,这里不进行分页
.set(GroupParams.GROUP_OFFSET,0)
//设置每个分组最多返回几条数据,这里设置一个比较大的数
.set(GroupParams.GROUP_LIMIT,100)
//是否返回总的组数
.set(GroupParams.GROUP_TOTAL_COUNT,true)
//组内排序
.set(GroupParams.GROUP_SORT,"credit_score asc")
//组间排序
.set(CommonParams.SORT,"credit_score desc");
需要注意的是,如果有需要,也可以按照多字段分别分组,如
.set(GroupParams.GROUP_FIELD,"brand_name","product_name")
另外,分组查询时有两种排序,分别是组内排序和组间排序
//组内排序
.set(GroupParams.GROUP_SORT,"credit_score asc")
//组间排序
.set(CommonParams.SORT,"credit_score desc");
经过测试,asc和desc均不可省略。
在组间排序时,如果从小到大排序,每个组取排序字段的最小值作为标识;
如果从大到小排序,则每个组取排序字段的最大值作为标识,最后根据各组标识进行排序。
不过这是我自行测试的结果,如果大家有不同意见欢迎提出。
之后对查询结果进行处理,分组查询返回的结果需要通过
与直接查询不同的方式获取。
//查询
QueryResponse response = solrserver.query(query);
//获取查询结果列表
GroupResponse groupResponse = response.getGroupResponse();
//获取根据不同分组方式查询到的结果
List<GroupCommand> groupCommandList = groupResponse.getValues();
//由于这里只有一种分组策略,所以直接取第一个对象
GroupCommand groupCommand = groupCommandList.get(0);
List<Group> groups = groupCommand.getValues();
//打印每个分组信息
SolrDocumentList list = null;
for (Group group:groups)
{
//获取每个分组内的数据
list = group.getResult();
System.out.println("------------");
for (SolrDocument solrDocument : list)
{
//方便演示,直接转换成json打印
String string = JSON.toJSONString(solrDocument);
System.out.println(string);
}
}
另外,如果你使用多个字段分别分组查询,那么
List groupCommandList = groupResponse.getValues();
这个list里就会有多个对象,代表不同分组方式查询到的结果
下面附上查询结果,注意这里我在组间使用credit_score字段倒序排序,
组内使用credit_score字段正序排序
可以看到查询结果按照brand_name字段分成了三组,组间倒序排序,组内正序排序