Solr Facet分组技术

本文探讨了美团CRM系统如何通过SolrCloud实现门店和项目信息的高效检索,并介绍了Facet技术在导航搜索中的应用。通过Facet查询,系统能够实时显示每个品类的POI数目和各个状态的DEAL数目,从而改善用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题背景

《搜索引擎关键字智能提示的一种实现》一文中介绍过,美团的CRM系统负责管理销售人员的门店(POI)和项目(DEAL)信息,提供统一的检索功能,其索引层采用的是SolrCloud。在用户搜索时,如果能直观地给出每个品类的POI数目,各个状态的DEAL数目,可以更好地引导用户进行搜索,进而提升搜索体验。

需求分析

例如,下图是用户搜索项目(DEAL)的界面,当选中一个人或者组织节点后,需要实时显示状态分组和快捷分组的每个项的DEAL数目:
项目搜索界面

为了实现上述导航效果,可以采用以下两个方案:

方案一, 针对每个导航项发送一个Ajax请求,去Solr服务器查询对应的DEAL数目。该方案问题在于,当导航项比较多时,扩展性不好。

方案二, 应用Solr自带的Facet技术实现以导航为目的的搜索,查询结果根据分类添加count信息。

DEAL的Solr索引设计如下:

schema.xml:
<field name="deal_id" type="int" indexed="true" stored="true" />       //deal id
<field name="title" type="text_ika" indexed="true" stored="false" />   //标题      
<field name="bd_id" type="int" indexed="true" stored="false" />        //负责人id
<field name="begin_time" type="long" indexed="true" stored="false" />  //项目开始时间
<field name="end_time" type="long" indexed="true" stored="false" />    //项目结束时间
<field name="status" type="int" indexed="true" stored="false" />       //项目状态
<field name="can_buy" type="boolean" indexed="true" stored="false" />  //是否可以购买
...省略     
本文的例子中用于facet的字段有status,can_buy,begin_time,end_time

注:
Facet的字段必须被索引,无需分词,无需存储。无需分词是因为该字段的值代表了一个整体概念,无需存储是因为一般而言用户所关心的并不是该字段的具体值,而是作为对查询结果进行分组的一种手段,用户一般会沿着这个分组进一步深入搜索。

Solr Facet简介

Facet是Solr的高级搜索功能之一,Solr作者给出的定义是导航(Guided Navigation)、参数化查询(Paramatic Search)。Facet的主要好处是在搜索的同时,可以按照Facet条件进行分组统计,给出导航信息,改善搜索体验。Facet搜索主要分为以下几类:

1. Field Facet
搜索结果按照Facet的字段分组并统计,Facet字段通过在请求中加入”facet.field”参数加以声明,如果需要对多个字段进行Facet查询,那么将该参数声明多次,Facet字段必须被索引。例如,以下表达式是以DEAL的status和can_buy属性为facet.field进行查询:

select?q=*:*&facet=true&facet.field=status&facet.field=can_buy&wt=json

Facet查询需要在请求参数中加入”facet=on”或者”facet=true”让Facet组件起作用,返回结果:

"facet_counts”: { 
     "facet_queries": {}, 
     "facet_fields":  { "status": [ "32", 96, 
                                     "0", 40, 
                                     "8", 81, 
                                    "16", 50, 
                                   "127", 80, 
                                    "64", 27 ] ,

                       "can_buy": [ "true", 236, 
                                    "false", 21 ]
                      }, 
     "facet_dates": {}, 
     "facet_ranges": {} 
 }

分组count信息包含在“facet_fields”中,分别按照"status"和“can_buy”的值分组,比如状态为32的DEAL数目有96个,能购买的DEAL数目(can_buy=true)是236。

Field Facet主要参数:

 facet.field:Facet的字段
 facet.prefix:Facet字段前缀
 facet.limit:Facet字段返回条数
 facet.offset:开始条数,偏移量,它与facet.limit配合使用可以达到分页的效果
 facet.mincount:Facet字段最小count,默认为0
 facet.missing:如果为on或true,那么将统计那些Facet字段值为null的记录
 facet.method:取值为enum或fc,默认为fc,fc表示Field Cache
 facet.enum.cache.minDf:当facet.method=enum时,参数起作用,文档内出现某个关键字的最少次数

2. Date Facet
日期类型的字段在索引中很常见,如DEAL上线时间,线下时间等,某些情况下需要针对这些字段进行Facet。时间字段的取值有无限性,用户往往关心的不是某个时间点而是某个时间段内的查询统计结果,Solr为日期字段提供了更为方便的查询统计方式。字段的类型必须是DateField(或其子类型)。需要注意的是,使用Date Facet时,字段名、起始时间、结束时间、时间间隔这4个参数都必须提供。
与Field Facet类似,Date Facet也可以对多个字段进行Facet。并且针对每个字段都可以单独设置参数。

3. Facet Query
Facet Query利用类似于filter query的语法提供了更为灵活的Facet。通过facet.query参数,可以对任意字段进行筛选。

基于Solr facet的实现

本文的例子,需要查询DEAL的“状态”和“快捷选项”导航信息。由于,有的状态DEAL数目不仅与状态(status)字段有关,还与开始时间(begin_time)和(end_time)相关,且各个快捷选项的DEAL数目的计算字段各不相同,要求比较灵活的查询,所以本文拟采用Facet Query方式实现。
以下代码是采用solrJ构造facet查询对象的过程:

public SolrQuery buildFacetQuery(Date now) {
    SolrQuery solrQuery = new SolrQuery();

    solrQuery.setFacet(true);//设置facet=on
    solrQuery.setFacetLimit(10);//限制facet返回的数量
    solrQuery.setQuery("*:*");

    long nowTime = now.getTime() / 1000;
    long minTime = minTimeStamp;
    long maxTime = maxTimeStamp;

    solrQuery.addFacetQuery("status:0");  //待撰写
    solrQuery.addFacetQuery("status:8");  //撰写中
    solrQuery.addFacetQuery("status:16"); //已终审
    solrQuery.addFacetQuery("status:32 AND " + "begin_time:[" + nowTime + " TO " + maxTime + " ]");      //已上架-待上线
    solrQuery.addFacetQuery("status:32 AND " + "begin_time:[" + minTime + " TO " + nowTime + "] AND " +  //已上架-上线中
            "end_time:[" + nowTime + " TO " + maxTime + " ]");
    solrQuery.addFacetQuery("status:32 AND " + "end_time:[" +  minTime + " TO " + nowTime + "]");  //已上架-已下线

    return solrQuery;
} 

说明:
"status:0" 查询满足条件的结果集中status=0的Deal数目,
"status:32 AND " + "begin_time:[" + nowTime + " TO " + maxTime + " ]”,查询满足条件的结果集中,status=32且begin_time大于现在时间的Deal数目,
依次类推

返回结果:

"status:0":756, 
"status:8":28,  
"status:16":21,  
"status:32 AND begin_time:[1401869128 TO 1956499199 ]":4,  
"status:32 AND begin_time:[0 TO 1401869128] AND end_time:[1401869128 TO 1956499199 ]":41,   
"status:32 AND end_time:[0 TO 1401869128]":10}

上述结果可知,“已上架-待上线”导航项对应的DEAL数为4个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值