原文出自:http://www.coin163.com/java/docs/201310/d_3010029802.html

一.   Facet 简介

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

二.   Facet 字段

1.       适宜被Facet 的字段

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

2.       Facet 字段的要求

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

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

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

3.       特殊情况

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

schema.xml

<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(org.apache.solr.handler.component.SearchHandler) 已经包含了 Facet 组件 (org.apache.solr.handler.component.FacetComponent). 如果自定义 requestHandler 或者对默认的 requestHandler 自定义组件列表 , 那么需要将 Facet 加入到组件列表中去 .

solrconfig.xml

<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 组件才起作用 .

1.       Field Facet

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 内的值 .

2.       Date Facet

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

需要注意的是 , 使用 Date Facet 时 , 字段名 , 起始时间 , 结束时间 , 时间间隔这 4 个参数都必须提供 .

与 Field Facet 类似 ,Date Facet 也可以对多个字段进行 Facet. 并且针对每个字段都可以单独设置参数 .

2.1   facet.date

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

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>

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

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

5.       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> facets = response.getFacetFields();//返回的facet列表

for (FacetField facet : facets) {

System.out.println(facet.getName());

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

List<Count> counts = facet.getValues();

for (Count count : counts) {

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

}

System.out.println();

}

solr facet查询及solrj 读取facet数据(相当有用)的更多相关文章

  1. solr facet查询及solrj 读取facet数据[转]

    solr facet查询及solrj 读取facet数据 | 所属分类:solr facet solrj 一.   Facet 简介 Facet 是 solr 的高级搜索功能之一 , 可以给用户提供更 ...

  2. Solr学习总结(六)SolrNet的高级用法(复杂查询,分页,高亮,Facet查询)

    上一篇,讲到了SolrNet的基本用法及CURD,这个算是SolrNet 的入门知识介绍吧,昨天写完之后,有朋友评论说,这些感觉都被写烂了.没错,这些基本的用法,在网上百度,资料肯定一大堆,有一些写的 ...

  3. Solr --- Group查询与Facet区别

    简介 facet的查询结果主要是分组信息:有什么分组,每个分组包括多少记录:但是分组中有哪些数据是不可知道的,只有进一步搜索. group则类似于关系数据库的group by,可以用于一个或者几个字段 ...

  4. Solr高级查询Facet

    一.什么是facet solr种以导航为目的的查询结果成为facet,在用户查询的结果上根据分类增加了count信息,然后用户根据count信息做进一步搜索. facet主要用于导航实现渐进式精确搜索 ...

  5. Solr的学习使用之(七)Solr高级查询facet、facet.pivot简介

    以下转载自:http://hongweiyi.com/2013/03/apache-solr-facet-introduction/ 1.什么是Faceted Search Facet['fæsɪt] ...

  6. SolrNet高级用法(分页、Facet查询、任意分组)

    前言 如果你在系统中用到了Solr的话,那么肯定会碰到从Solr中反推数据的需求,基于数据库数据生产索引后,那么Solr索引的数据相对准确,在电商需求中经常会碰到菜单.导航分类(比如电脑.PC的话会有 ...

  7. 8.2Solr API使用(Facet查询)

    转载请出自出处:http://eksliang.iteye.com/blog/2165882 一)概述 Facet是solr的高级搜索功能之一,可以给用户提供更友好的搜索体验.在搜索关键字的同时,能够 ...

  8. lucene搜索之facet查询原理和facet查询实例——TODO

    转自:http://www.lai18.com/content/7084969.html Facet说明 我们在浏览网站的时候,经常会遇到按某一类条件查询的情况,这种情况尤以电商网站最多,以天猫商城为 ...

  9. solr开发从查询结果集中获取对象数据

    solrJ从查询结果集中获取对象数据. 方案一:自定义转换方式 /** * * SolrDocument与实体类转换 [测试通过] * * @author pudongping * * @param ...

随机推荐

  1. ROS新版本Lunar Loggerhead

    参考链接: 1 http://wiki.ros.org/lunar 2 http://wiki.ros.org/lunar/Installation 3 http://docs.ros.org/ 4  ...

  2. php果然是世界上最好的语言

    这两天参加Hackathon,作为一个什么都半吊子的家伙,两人小队伍被逼上岗,于是我不得不着手写代码.由此,我体验到了php的魔力-- 首先,我深刻地意识到了更新版本的重要性. 偷懒不想搭Apache ...

  3. 【ES6】箭头函数

    let getPrices = () => 4.55 console.log(getPrices()) let arr = ['apple', 'banana', 'orange'] arr.f ...

  4. CS与BS区别

    简介:CS即Client/Server(客户机/服务器)结构,C/S结构在技术上很成熟,它的主要特点是交互性强.具有安全的存取模式.网络通信量低.响应速度快.利于处理大量数据.但是该结构的程序是针对性 ...

  5. test20181219(期末考试)

    Written with StackEdit. \(noip\)爆炸后就好久没考试了...结果今天又被抓去,感觉很慌啊... 考完了.过来填坑. T1 Description 使得\(x^x\)达到或 ...

  6. JAVA软件配置—环境变量

    环境Windows10,JDK,JRE1.8.0_102 鼠标右击左下角Windows图标,选择"系统"项: 点击"高级系统设置"——"环境变量&qu ...

  7. iOS10修改电池状态栏的方法

  8. 在Spring中通过构造自动装配--constructor

    在Spring中,可以使用“通过构造自动装配”,实际上是按构造函数的参数类型自动装配. 这意味着,如果一个bean的数据类型与其他bean的构造器参数的数据类型是相同的,那么将自动装配. packag ...

  9. Free Online SQL Formatter

    SQL Formatter Web Service Free Online SQL Formatter SQL Parser engine used by SQL formatter 今日找了几个在线 ...

  10. SublimeText3常用插件安装与使用

    packagecontroller的安装 https://packagecontrol.io/ 安装了它就可以更好的进行插件的安装和管理 复制代码,打开控制面板[ctrl+·]将代码拷贝,即可进行安装 ...