设为首页 收藏本站
查看: 1293|回复: 0

[经验分享] solr facet查询及solrj 读取facet数据[转]

[复制链接]

尚未签到

发表于 2017-12-19 12:35:27 | 显示全部楼层 |阅读模式
  一.   Facet 简介
  Facet 是 solr 的高级搜索功能之一 , 可以给用户提供更友好的搜索体验 . 在搜索关键字的同时, 能够按照 Facet 的字段进行分组并统计 .
  二.   Facet 字段

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

  • Facet 字段的要求
  Facet 的字段必须被索引 . 一般来说该字段无需分词 , 无需存储 .
  无需分词是因为该字段的值代表了一个整体概念 , 如电脑的品牌 ” 联想 ” 代表了一个整体概念 , 如果拆成 ” 联 ”,” 想 ” 两个字都不具有实际意义 . 另外该字段的值无需进行大小写转换等处理 , 保持其原貌即可 .
  无需存储是因为一般而言用户所关心的并不是该字段的具体值 , 而是作为对查询结果进行分组的一种手段 , 用户一般会沿着这个分组进一步深入搜索 .

  • 特殊情况
  对于一般查询而言 , 分词和存储都是必要的 . 比如 CPU 类型 ”Intel 酷睿 2 双核 P7570”, 拆分成 ”Intel”,” 酷睿 ”,”P7570” 这样一些关键字并分别索引 , 可能提供更好的搜索体验 . 但是如果将 CPU 作为 Facet 字段 , 最好不进行分词 . 这样就造成了矛盾 ,解决方法为 , 将 CPU 字段设置为不分词不存储 , 然后建立另外一个字段为它的 COPY, 对这个 COPY 的字段进行分词和存储 .
  schema.xml
  <types>
  <fieldType name="string" omitNorms="true"/>
  <fieldType name="tokened" >
  <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(org.apache.solr.handler.component.SearchHandler) 已经包含了Facet 组件 (org.apache.solr.handler.component.FacetComponent). 如果自定义 requestHandler 或者对默认的 requestHandler 自定义组件列表 , 那么需要将 Facet 加入到组件列表中去 .
  solrconfig.xml
  <requestHandler name="standard" default="true">
  ……
  <arr name="components">
  <str>自定义组件名</str>
  <str>facet</str>
  ……
  </arr>
  </requestHandler>
  四.   Facet 查询
  进行 Facet 查询需要在请求参数中加入 ”facet=on” 或者 ”facet=true” 只有这样 Facet 组件才起作用 .
    Field>
  Facet 字段通过在请求中加入 ”facet.field” 参数加以声明 , 如果需要对多个字段进行 Facet 查询 , 那么将该参数声明多次 . 比如
  /select?q=联想
  &facet=on
  &facet.field=cpu
  &facet.field=videoCard
  返回结果 :
  <lst name="facet_counts">
  <lst name="facet_queries"/>
  <lst name="facet_fields">
  <lst name="cpu">
  <int name="Intel 酷睿2双核 T6600">48</int>
  <int name="Intel 奔腾双核 T4300">28</int>
  <int name="Intel 酷睿2双核 P8700">18</int>
  <int name="Intel 酷睿2双核 T6570">11</int>
  <int name="Intel 酷睿2双核 T6670">11</int>
  <int name="Intel 奔腾双核 T4400">9</int>
  <int name="Intel 酷睿2双核 P7450">9</int>
  <int name="Intel 酷睿2双核 T5870">8</int>
  <int name="Intel 赛扬双核 T3000">7</int>
  <int name="Intel 奔腾双核 SU4100">6</int>
  <int name="Intel 酷睿2双核 P8400">6</int>
  <int name="Intel 酷睿2双核 SU7300">5</int>
  <int name="Intel 酷睿 i3 330M">4</int>
  </lst>
  <lst name="videoCard">
  <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>
  <int name="NVIDIA GeForce G 103M">8</int>
  <int name="NVIDIA GeForce GT 220M">8</int>
  <int name="NVIDIA GeForce 9400M G">7</int>
  <int name="NVIDIA GeForce G 210M">6</int>
  </lst>
  </lst>
  <lst name="facet_dates"/>
  </lst>
  各个 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 内的值 .
    Date>
  日期类型的字段在文档中很常见 , 如商品上市时间 , 货物出仓时间 , 书籍上架时间等等 .某些情况下需要针对这些字段进行 Facet. 不过时间字段的取值有无限性 , 用户往往关心的不是某个时间点而是某个时间段内的查询统计结果 . Solr 为日期字段提供了更为方便的查询统计方式 . 当然 , 字段的类型必须是 DateField( 或其子类型 ).

  需要注意的是 , 使用 Date>
  与 Field>  2.1   facet.date

  该参数表示需要进行 Date>  2.2   facet.date.start
  起始时间 , 时间的一般格式为 ” 1995-12-31T23:59:59Z”, 另外可以使用 ”NOW”,”YEAR”,”MONTH” 等等 , 具体格式可以参考 org.apache.solr.schema. DateField 的 java doc.
  2.3   facet.date.end
  结束时间 .
  2.4   facet.date.gap
  时间间隔 . 如果 start 为 2009-1-1,end 为 2010-1-1.gap 设置为 ”+1MONTH” 表示间隔 1 个月 , 那么将会把这段时间划分为 12 个间隔段 . 注意 ”+” 因为是特殊字符所以应该用 ”%2B” 代替 .
  2.5   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.
  2.6   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
返回结果 :  <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">+1MONTH</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:0Z TO 2009-2-1T0:0:0Z]
  &facet.query=date:[2009-4-1T0:0:0Z 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="Intel 酷睿2双核 T6600">48</int>
  <int name="Intel 奔腾双核 T4300">28</int>
  <int name="Intel 酷睿2双核 P8700">18</int>
  <int name="Intel 酷睿2双核 T6570">11</int>
  <int name="Intel 酷睿2双核 T6670">11</int>
  <int name="Intel 奔腾双核 T4400">9</int>
  <int name="Intel 酷睿2双核 P7450">9</int>
  <int name="Intel 酷睿2双核 T5870">8</int>
  <int name="Intel 赛扬双核 T3000">7</int>
  <int name="Intel 奔腾双核 SU4100">6</int>
  <int name="Intel 酷睿2双核 P8400">6</int>
  <int name="Intel 酷睿2双核 SU7300">5</int>
  <int name="Intel 酷睿 i3 330M">4</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>
  <int name="NVIDIA GeForce G 103M">8</int>
  <int name="NVIDIA GeForce GT 220M">8</int>
  <int name="NVIDIA GeForce 9400M G">7</int>
  <int name="NVIDIA GeForce G 210M">6</int>
  </lst>
  </lst>
  <lst name="facet_dates"/>
  </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>
  <int name="11.6">0</int>
  <int name="12.1">0</int>
  <int name="13.1">0</int>
  <int name="13.3">0</int>
  <int name="14.1">0</int>
  <int name="15.4">0</int>
  <int name="15.5">0</int>
  <int name="15.6">0</int>
  <int name="16.0">0</int>
  <int name="17.0">0</int>
  <int name="17.3">0</int>
  </lst>
  </lst>
  <lst name="facet_dates"/>
  </lst>
  可以看到 , 屏幕尺寸 (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 的支持
SolrServer server = getSolrServer();//获取SolrServer

SolrQuery query = new SolrQuery();//建立一个新的查询

query.setQuery("*:*");

query.setFacet(true);//设置facet=on

query.addFacetField(new String[] { "cpu", "videoCard" });//设置需要facet的字段

query.setFacetLimit(10);//限制facet返回的数量

QueryResponse response = server.query(query);


List<FacetField>>
for (FacetField facet :>
System.out.println(facet.getName());

    System.out.println("----------------");


    List<Count> counts =>
    for (Count count : counts) {

        System.out.println(count.getName() + ":" + count.getCount());

    }

    System.out.println();

  }

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-425695-1-1.html 上篇帖子: Solr的原理及在项目中的使用实例 下篇帖子: (转)淘淘商城系列
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表