Solr之分组统计。

        本文实现分组统计的方法是使用了Solr的Facet组件,Facet组件是Solr默认集成的一个组件,Facet组件是Solr默认集成的一个组件。

Facet简介

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

       

Facet字段

  • 适宜被Facet的字段

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

  • Facet字段的要求

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

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

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

  • 特殊情况

对于一般查询而言,分词和存储都是必要的,比如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已经包含了Fact组件(solr.FacetComponent)。如果自定义requestHandler或者对默认的requestHandler自定义组件列表,那么需要将Facet加入到组件列表中。

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

......

<arr name = "components">

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

<str>facet</str>

......

</arr>

Facet查询

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

Field Facet

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

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

        返回结果:

<?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_l">

<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

  • facet.prefix

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

  • facet.sort

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

  • facet.limit

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

  • facet.offset

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

  • facet.mincount

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

  • facet.missing

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

  • facet.method

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

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

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

  • facet.enum.cache.minDf

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

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设置为+1 MONTH表示间隔1个月,那么将会把这段时间划分为12个间隔段。

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

        facet.date.hardend:取值可以为true|false,默认为false。它表示gap迭代到end处采用何种处理。

举例说明:start为2009-1-1,end为2009-12-25,gap为+1 MONTH,

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.end=2009-1-1T0:0:0Z

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

&facet.date.gap=%2B1MONTH

&facet.date.other=all

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries" />

<lst name = "facet_fields" />

<lst name = "facet_dates" >

<int name = "2009-01-01T00:00:00Z">5</int>

<int name = "2009-02-01T00:00:00Z">7</int>

<int name = "2009-03-01T00:00:00Z">4</int>

<int name = "2009-04-01T00:00:00Z">3</int>

<int name = "2009-05-01T00:00:00Z">7</int>

<int name = "2009-06-01T00:00:00Z">3</int>

<int name = "2009-07-01T00:00:00Z">6</int>

<int name = "2009-08-01T00:00:00Z">7</int>

<int name = "2009-09-01T00:00:00Z">2</int>

<int name = "2009-10-01T00:00:00Z">4</int>

<int name = "2009-11-01T00:00:00Z">1</int>

<int name = "2009-12-01T00:00:00Z">5</int>

<str name = "gap">+1 MONTH</str>

<date name = "end">2010-01-01T00:00:00Z</date>

<int name = "before">180</int>

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

<int name = "between">54</int>

</lst>

</lst>

Facet Query

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

  • 例1

&facet=on

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

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

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries">

<int name = "date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]">5</int>

<int name = "date:[2009-4-1T0:0:0Z TO 2009-5-1T0:0:0Z]">3</int>

</lst>

<lst name = "facet_fields" />

<lst name = "facet_dates" />

</lst>

  • 例2

&facet=on

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

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

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries">

<int name = "date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]">5</int>

<int name = "price:[* TO 5000]">116</int>

</lst>

<lst name = "facet_fields" />

<lst name = "facet_dates" />

</lst>

  • 例3:

&facet=on

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

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries">

<int name = "cpu:[A TO G]">11</int>

</lst>

<lst name = "facet_fields" />

<lst name = "facet_dates" />

</lst>

key 操作符

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

例:

&facet=on

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

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

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries" />

<lst name = "facet_fields" />

<lst name = "中央处理器">

<int name = "Inter 酷睿 2双核 T6600">48</int>

<int name = "Inter 奔腾双核 T4300">28</int>

<int name = "Intel 酷睿 2双核 P8700">18</int>

<int name = "Intel 赛扬双核 T3000">7</int>

</lst>

<lst name = "显卡">

<int name = "ATI Mobility Radeon HD 4">63</int>

<int name = "NVIDIA GeForce G 105M">24</int>

<int name = "NVIDIA GeForce GT 240M">21</int>

</lst>

</lst>

tag操作符和ex操作符

       当查询使用filter query的时候,如果filter query的字段正好是Facet字段,那么查询结果往往被限制在某一个值内。

例:

&fq=screenSize:14

&facet=on

&facet.field=screenSize

返回结果:

<lst name = "facet_counts">

<lst name = "facet_queries" />

<lst name = "facet_fields" >

<lst name = "screenSize">

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

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

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

</lst>

</lst>

<lst name = "facet_dates" />

</lst>

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

例:

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

&facet=on

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

返回结果:

<lst name = "facet_count" >

<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>

</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"); // 增加分组字段

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();

    • 1
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    ### 回答1: 如果你想在Solr中执行分组查询,并且你的字段包含多个值,你可以使用Solr的多值分组功能。为了使用这个功能,你需要使用Solr分组查询语法,并在查询中指定“group.field”参数来指定要分组的字段。然后,您可以使用Solr的“group.limit”参数来指定每个分组中包含的文档数的最大值。这将确保您的分组查询结果仅包含与每个分组相关的最相关文档。从Solr 4.0开始,您还可以使用Solr的“group.format”参数来指定分组查询结果的格式,以便更好地满足您的需求。 ### 回答2: Solr是一个强大的搜索引擎,可以用于进行高效的分组查询。当我们需要对包含多个值的字段进行分组查询时,可以通过使用Solr的facet功能来实现。 在Solr中,可以使用facet.field参数指定要进行分组的多值字段。例如,如果我们有一个字段名为"tags",该字段包含多个标签,可以通过将facet.field设置为"tags"来进行分组查询。在搜索请求中,我们需要设置facet参数为true来启用分组查询。 当我们执行搜索请求时,Solr会计算每个标签的出现次数,并返回每个标签及其对应的文档数。这样,我们可以获得每个标签的分组统计信息。 我们还可以通过设置facet.limit参数来限制返回的分组结果数量。如果我们想要获取前n个最常见的标签,可以将facet.limit设置为n。 另外,我们还可以对分组结果进行排序,以便按照某个特定的标准对标签进行排序。例如,我们可以使用facet.sort参数将分组结果按照文档数目或者标签名称进行排序。 除了对整个多值字段进行分组查询,我们还可以在分组查询中指定条件。例如,我们可以使用facet.query参数来指定额外的条件,并对满足条件的文档进行分组查询。 总结来说,Solr可以通过使用facet功能对包含多个值的字段进行分组查询。我们可以指定要进行分组的字段,并可以设置额外的条件、排序和限制来获取所需的分组统计信息。 ### 回答3: Solr是一个开源的搜索平台,它支持多值字段的分组查询。在Solr中,可以使用facet查询来实现分组查询,并且可以应用于包含多值的字段。 要对包含多值的字段进行分组查询,首先需要在solrconfig.xml文件中配置相应的字段类型。可以使用Solr提供的一些已有的多值字段类型,例如"string_mv"、"text_general_mv"等,也可以根据需要自定义字段类型。 在查询时,可以使用facet.field参数指定需要进行分组查询的字段名。当指定的字段是一个多值字段时,Solr会根据每个值进行分组。结果中将包含该字段的每个值作为分组的key,并统计每个分组出现的次数。 例如,假设有一个包含多个标签的字段"tags",现在需要对"tags"字段进行分组查询。可以使用如下查询语句: ``` /select?q=*:*&facet=true&facet.field=tags ``` 执行该查询后,Solr将返回一个结果集,其中包含了"tags"字段的每个值作为分组的key,并统计了每个分组出现的次数。这样就实现了对包含多值的字段进行分组查询。 需要注意的是,对于大量数据或者需要更复杂的聚合操作的情况,可能需要使用更高级的分组查询功能,例如利用facet.pivot参数进行多级分组或者使用facet.query参数进行条件过滤等。 综上所述,Solr支持对包含多值的字段进行分组查询,通过配置字段类型和使用facet查询参数,可以轻松实现这一功能。

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值