Solr---Facet分面查询

13 篇文章 0 订阅

场景描述:

      Solr具有分面查询的功能,其中包含字段分面、间隔分面、区间分面。网上讲的都是字段分面,区间分面少之又少,而且通过solrj从java查询的文章也少的可怜,所以在这里,讲一下我是如何操作的。

设置分面参数:

// 创建solrQuery对象
SolrQuery query = new SolrQuery();
...
//设置分面
query.setFacet(true); // 设置使用facet
query.setFacetMinCount(1); // 设置facet最少的统计数量
query.setFacetLimit(10); // facet结果的返回行数

字段分面:

/*字段分面*/
query.addFacetField("FILE_TYPE"); // facet的字段 文档类型
query.addFacetField("DISEASE_TYPE"); // facet的字段 疾病
query.addFacetField("DEPT_NAME"); // facet的字段 科室
query.addFacetField("SEX"); // facet的字段 性别
...
// 执行搜索,返回response对象
QueryResponse rq = cloudSolrClient.query(query);
/*字段分面*/
List<FacetField> flist=rq.getFacetFields();
// 格式为:{分面字段:{字段内容:计数}...},比如{SEX:{"男":17,"女":15},DEPT_NAME:{...}...}
JSONObject facetJson = new JSONObject();
// 格式为:{字段内容:计数},比如{"男":17}
JSONObject facetContentJson = new JSONObject();
for(FacetField ff : flist) {
    // 每次清空之前的内容
    facetContentJson.clear();
    // 这里采用全名,是为了避免与其他分面的变量名同为Count的问题
    for(org.apache.solr.client.solrj.response.FacetField.Count c:ff.getValues()) {
        facetContentJson.put(c.getName(), c.getCount());
    }
    facetJson.accumulate(ff.getName(), facetContentJson );   
}

间隔分面:

/*间隔分面*/
query.addIntervalFacets("AGE",new String[]{"[0,1]","(1,14]","[15,35]","(35,60]","(60,*]"}); 
/* 间隔分面*/
//年龄间隔分面
for (IntervalFacet intervalFacet:rq.getIntervalFacets()){
    // 清空之前数据
    facetContentJson.clear();
    for( IntervalFacet.Count c:intervalFacet.getIntervals()) {
        //区间分面内容【0-1】,(1,14】,【15,35】,(35,60】,(60,*】
        switch (i){
            case 0:
                if (c.getCount()==0){
                    break;
                }else{
                    facetContentJson.put("0-1岁", c.getCount());
                    break;
                }

            case 1:
                if (c.getCount()==0){
                    break;
                }else{
                    facetContentJson.put("1-14岁", c.getCount());
                    break;
                }

            case 2:
                if (c.getCount()==0){
                    break;
                }else{
                    facetContentJson.put("15-35岁", c.getCount());
                    break;
                }
            case 3:
                if (c.getCount()==0){
                    break;
                }else{
                    facetContentJson.put("35-60岁", c.getCount());
                    break;
                }
            case 4:
                if (c.getCount()==0){
                    break;
                }else{
                    facetContentJson.put("60岁以上", c.getCount());
                    break;
                }
            default:
                break;
        }
    }
    facetJson.accumulate(intervalFacet.getField(), facetContentJson);
}

时间区间分面:

/*时间区间分面*/
// 2010-今年
// 时间对象
Calendar cal = Calendar.getInstance();
// 设置当前时间为加8小时,因为时区的问题,在处理之后发送查询条件中是减过8小时的所以这里,加上8小时
cal.add(Calendar.HOUR,+8);
// java时间格式
SimpleDateFormat ymdhmsSdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 设置solr时间格式
SimpleDateFormat solrSdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
// 按月分
query.addDateRangeFacet("CREATE_TIME", ymdhmsSdf.parse("2010-01-01 08:00:00"),cal.getTime() , "+1MONTH");
/* 时间区间分面*/
@SuppressWarnings("rawtypes")
List<RangeFacet> rlist=rq.getFacetRanges();
if(rlist!=null&&rlist.size()>0){
    for(int i=0;i<rlist.size();i++) {
        List<org.apache.solr.client.solrj.response.RangeFacet.Count> clist=rlist.get(i).getCounts();
        // 清空之前数据
        facetContentJson.clear();
        // 将月份与月份对应的结果放入的分面json中
        for(int j=clist.size()-1;j>=0;j--) {
            facetContentJson.put(ymSdf.format(solrSdf.parse(clist.get(j).getValue())), clist.get(j).getCount());
        }
        facetJson.accumulate(rlist.get(i).getName(), facetContentJson);
    }
}

        该方法(addDateRangeFacet)是针对时间的,其中作为时间区间分面的字段在Solr配置文件中需要设置为时间格式,还有一个方法是针对数字区间的(addNumericRangeFacet)。其中时间区间的方法最后一个参数是时间间隔“gap”为字符串属性,内容为”+1YEAR”,”+1MONTHS”,”+1DAY”,”+1HOUR”。

总结:

    结果的结构里都有Count类型数据,但是字段分面的是FacetField.Count,区间分面的是RangeFacet.Count,所以在遍历Count属性的List时候,我是将整个包名放在上面,如果你只用到两种分面中的一种,则不需要这样写,只导入你用的那个包就够了。其中可以注意到,从Solr里获取到的时间格式为:"yyyy-MM-dd'T'HH:mm:ss'Z'",这个是Solr固定的时间格式。

注意事项:

1.在后续时间处理诸如,query.addFilterQuery(entry.getKey()+":["+solrSdf.format(sdf.parse((String) entry.getValue()))+" TO NOW]");这样的时间处理时,格式需要特别注意,“TO”两边的空格也不能漏掉。“]”代表包含,“}”代表不包含;

2.时间区间的查询时间范围,因为时区的问题,增加了8小时;原因请参考我的这一篇

3.java中的时间格式“YYYY”与“yyyy”是两种概念也需要注意,不能写错了。



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值