solr 分组统计

我这里实现分组统计的方法是使用了Solr的Facet组件, Facet组件是Solr默认集成的一个组件.

Facet是solr的高级搜索功能之一,可以给用户提供更友好的搜索体验.在搜索关键字的同时,能够按照Facet的字段进行分组并统计

  1. 适宜被Facet的字段

    一般代表了实体的某种公共属性,如商品的分类,商品的制造厂家,书籍的出版商等等.

  2. Facet字段的要求

    Facet的字段必须被索引.一般来说该字段无需分词,无需存储.

    无需分词是因为该字段的值代表了一个整体概念,如电脑的品牌”联想”代表了一个整 体概念,如果拆成”联”,”想”两个字都不具有实际意义.另外该字段的值无需进行大小 写转换等处理,保持其原貌即可.

    无需存储是因为一般而言用户所关心的并不是该字段的具体值,而是作为对查询结果进 行分组的一种手段,用户一般会沿着这个分组进一步深入搜索.

  3. 特殊情况

    对于一般查询而言,分词和存储都是必要的.比如CPU类型”Intel 酷睿2双核 P7570”, 拆分成”Intel”,”酷睿”,”P7570”这样一些关键字并分别索引,可能提供更好的搜索 体验.但是如果将CPU作为Facet字段,最好不进行分词.这样就造成了矛盾,解决方法为, 将CPU字段设置为不分词不存储,然后建立另外一个字段为它的COPY,对这个COPY的 字段进行分词和存储.

<types>

         <fieldType name="string" class="solr.StrField" omitNorms="true"/>

         <fieldType name="tokened" class="solr.TextField" >

                   <analyzer>

                   ……

                   </analyzer>

         </fieldType>

</types>

<fields>

         <field name="cpu" type="string" indexed="true" stored="false"/>

         <field name="cpuCopy” type=" tokened" indexed="true" stored="true"/>

</fields>

<copyField source="cpu" dest="cpuCopy"/>

Facet组件
Solr的默认requestHandler已经包含了Facet组件(solr.FacetComponent).如果自定义requestHandler或者对默认的requestHandler自定义组件列表,那么需要将Facet加入到组件列表中去.



<requestHandler name="standard" class="solr.SearchHandler" default="true">

……

<arr name="components">

<str>自定义组件名</str>

<str>facet</str>

……

</arr>

</requestHandler>

Facet查询
进行Facet查询需要在请求参数中加入facet=on或者facet=true只有这样Facet组件才起作用.

Field Face

Facet字段通过在请求中加入facet.field参数加以声明,如果需要对多个字段进行Facet查询,那么将该参数声明多次.例如:

http://localhost:8983/solr/ collection1/select?q=*%3A*&start=0&rows=1&wt=xml&indent=true&facet=true&facet.field=category_s&facet.field=modified_l

返回结果:

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="facet">true</str>
    <str name="indent">true</str>
    <str name="start">0</str>
    <str name="q">*:*</str>
<arr name="facet.field"> 
   <str>category_s</str> 
   <str>modified_l</str> 
</arr>
    <str name="wt">xml</str>
    <str name="rows">0</str>
  </lst>
</lst>
<result name="response" numFound="17971" start="0">
</result>
<lst name="facet_counts">
  <lst name="facet_queries"/>
  <lst name="facet_fields">
    <lst name="category_s">
      <int name="0">5991</int>
      <int name="1">5990</int>
      <int name="2">5990</int>
</lst>
    <lst name="modified_l">
      <int name="1162438554000">951</int>
      <int name="1162438556000">917</int>
      <int name="1162438548000">902</int>
      <int name="1162438546000">674</int>
    </lst>
  </lst>
  <lst name="facet_dates"/>
  <lst name="facet_ranges"/>
</lst>
</response>


各个Facet字段互不影响,且可以针对每个Facet字段设置查询参数.以下介绍的参数既可以应用于所有的Facet字段,也可以应用于每个单独的Facet字段.应用于单独的字段时通过

f.字段名.参数名=参数值

这种方式调用.比如facet.prefix参数应用于cpu字段,可以采用如下形式

f.cpu.facet.prefix=Intel

1.1 facet.prefix

   表示Facet字段值的前缀.比如facet.field=cpu&facet.prefix=Intel,那么对cpu字段进行Facet查询,返回的cpu都是以Intel开头的, AMD开头的cpu型号将不会被统计在内.

1.2 facet.sort

表示Facet字段值以哪种顺序返回.可接受的值为true(count)|false(index,lex). true(count)表示按照count值从大到小排列. false(index,lex)表示按照字段值的自然顺序(字母,数字的顺序)排列.默认情况下为true(count).当facet.limit值为负数时,默认facet.sort= false(index,lex).

1.3 facet.limit

   限制Facet字段返回的结果条数.默认值为100.如果此值为负数,表示不限制.

1.4 facet.offset

   返回结果集的偏移量,默认为0.它与facet.limit配合使用可以达到分页的效果.

1.5 facet.mincount

限制了Facet字段值的最小count,默认为0.合理设置该参数可以将用户的关注点集中在少数比较热门的领域.

1.6 facet.missing

   默认为””,如果设置为true或者on,那么将统计那些该Facet字段值为null的记录.

1.7 facet.method
取值为enum或fc,默认为fc.该字段表示了两种Facet的算法,与执行效率相关.

enum适用于字段值比较少的情况,比如字段类型为布尔型,或者字段表示中国的所有省份.Solr会遍历该字段的所有取值,并从filterCache里为每个值分配一个filter(这里要求solrconfig.xml里对filterCache的设置足够大).然后计算每个filter与主查询的交集.

fc(表示Field Cache)适用于字段取值比较多,但在每个文档里出现次数比较少的情况.Solr会遍历所有的文档,在每个文档内搜索Cache内的值,如果找到就将Cache内该值的count加1.

1.8 facet.enum.cache.minDf

当facet.method=enum时,此参数其作用,minDf表示minimum document frequency.也就是文档内出现某个关键字的最少次数.该参数默认值为0.设置该参数可以减少filterCache的内存消耗,但会增加总的查询时间(计算交集的时间增加了).如果设置该值的话,官方文档建议优先尝试25-50内的值.

6.6.3 Date Facet
日期类型的字段在文档中很常见,如商品上市时间,货物出仓时间,书籍上架时间等等.某些情况下需要针对这些字段进行Facet.不过时间字段的取值有无限性,用户往往关心的不是某个时间点而是某个时间段内的查询统计结果. Solr为日期字段提供了更为方便的查询统计方式.当然,字段的类型必须是DateField(或其子类型).

需要注意的是,使用Date Facet时,字段名,起始时间,结束时间,时间间隔这4个参数都必须提供.与Field Facet类似,Date Facet也可以对多个字段进行Facet.并且针对每个字段都可以单独设置参数.

facet.date:该参数表示需要进行Date Facet的字段名,与facet.field一样,该参数可以被设置多次,表示对多个字段进行Date Facet.

facet.date.start:起始时间,时间的一般格式为1995-12-31T23:59:59Z,另外可以使用NOW\YEAR\ MONTH等等,具体格式可以参考DateField的Java doc.

facet.date.end:结束时间.

facet.date.gap:时间间隔.如果start为2009-1-1,end为2010-1-1.gap设置为+1MONTH表示间隔1个月,那么将会把这段时间划分为12个间隔段.

注意+因为是特殊字符所以应该用%2B代替.

facet.date.hardend:取值可以为true|false,默认为false.它表示gap迭代到end处采用何种处理.举例说明start为2009-1-1,end为2009-12-25,gap为+1MONTH,

hardend为false的话最后一个时间段为2009-12-1至2010-1-1;

hardend为true的话最后一个时间段为2009-12-1至2009-12-25.

facet.date.other:取值范围为before|after|between|none|all,默认为none.before会对start之前的值做统计.after会对end之后的值做统计.between会对start至end之间所有值做统计.如果hardend为true的话,那么该值就是各个时间段统计值的和.none表示该项禁用.all表示before,after,all都会统计.

举例:

&facet=on

&facet.date=date

&facet.date.start=2009-1-1T0:0:0Z

&facet.date.end=2010-1-1T0:0:0Z

&facet.date.gap=%2B1MONTH

&facet.date.other=all

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

例1:

&facet=on

&facet.query=date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]

&facet.query=date:[2009-4-1T0:0:0Z TO 2009-5-1T0:0:0Z]

例2:

&facet=on

&facet.query=date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]

&facet.query=price:[* TO 5000]

例3:

&facet=on

&facet.query=cpu:[A TO G]

6.6.5 key操作符
可以用key操作符为Facet字段取一个别名.

例:

&facet=on

&facet.field={!key=中央处理器}cpu

&facet.field={!key=显卡}videoCard

6.6.6 tag操作符和ex操作符
当查询使用filter query的时候,如果filter query的字段正好是Facet字段,那么查询结果往往被限制在某一个值内.

例:

&fq=screenSize:14

&facet=on

&facet.field=screenSize

可以看到,屏幕尺寸(screenSize)为14寸的产品共有107件,其它尺寸的产品的数目都是0,这是因为在filter里已经限制了screenSize:14.这样,查询结果中,除了screenSize=14的这一项之外,其它项目没有实际的意义.有些时候,用户希望把结果限制在某一范围内,又希望查看该范围外的概况.比如上述情况,既要把查询结果限制在14寸屏的笔记本,又想查看一下其它屏幕尺寸的笔记本有多少产品.这个时候需要用到tag和ex操作符.tag就是把一个filter标记起来,ex(exclude)是在Facet的时候把标记过的filter排除在外.

例:

&fq={!tag=aa}screenSize:14

&facet=on

&facet.field={!ex=aa}screenSize

返回结果:

<lst name="facet_counts">

       <lst name="facet_queries"/>

       <lst name="facet_fields">

              <lst name=" screenSize">

                     <int name="14.0">107</int>

<int name="14.1">40</int>

<int name="13.3">34</int>

<int name="15.6">22</int>

<int name="15.4">8</int>

<int name="11.6">6</int>

<int name="12.1">5</int>

<int name="16.0">5</int>

<int name="15.5">3</int>

<int name="17.0">3</int>

<int name="17.3">3</int>

<int name="10.2">1</int>

<int name="11.1">1</int>

<int name="13.1">1</int>

</lst>

       </lst>

       <lst name="facet_dates"/>

</lst>

这样其它屏幕尺寸的统计信息就有意义了.

SolrJ对Facet的支持
//初始化查询对象

String q = “.”;

SolrQuery query = new SolrQuery(q);

query.setIncludeScore(false);//是否按每组数量高低排序

query.setFacet(true);//是否分组查询

query.setRows(0);//设置返回结果条数,如果你时分组查询,你就设置为0

query.addFacetField(“modified_l”);//增加分组字段 q

query.addFacetQuery (“category_s[0 TO 1]”);

QueryResponse rsp = server.query(query);


取出结果

List<FacetField.Count> list = rsp.getFacetField(“modified_l”).getValues();
Map<String, Integer> list = rsp.getFacetQuery();

贡献 http://blog.csdn.net/awj3584/article/details/16963525

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值