分面搜索(Faceting)是基于索引词对搜索结果进行分类整理的功能。
搜索者可以看到索引词和对应匹配文档的数量统计,分面搜索使用户可以轻松地探索搜索结果,精确定位到所需的结果。
另外,还可以参考JSON分面API了解另一种实现方法。
通用分面参数
有两个控制分面功能的通用参数。
facet
必需性 | 默认值 |
---|---|
必需 | false |
如果设为true
,此参数会在查询响应中启用分面计数。如果设为false
、空白或缺失,则禁用分面功能。除非此参数设为true
,否则下面列出的其他参数都不会生效。
facet.query
必需性 | 默认值 |
---|---|
可选 | 无 |
指定一个使用Lucene默认语法的任意查询来生成分面计数。
默认情况下,Solr的分面功能会自动确定字段的唯一词并返回每个词的计数。使用facet.query
,你可以覆盖这个默认行为,精确选择要统计的词或表达式。在典型的分面实现中,你会指定多个facet.query
参数。这个参数对于基于数值范围的分面或基于前缀的分面特别有用。
你可以多次设置facet.query
参数,表示应该将多个查询用作独立的分面约束。
要在非默认语法中使用分面查询,请在分面查询前加上查询符号的名称。例如,要使用假设的myfunc
查询解析器,可以这样设置facet.query
参数:
1 | facet.query={!myfunc}name~fred |
字段值分面参数
可以使用多个参数来触发基于字段中索引词的分面。
使用这些参数时,重要的是要记住”词”在Lucene中是一个非常特定的概念:它关系到分析后索引的字面字段/值对。对于包含词干提取、小写化或单词分割的文本字段,生成的词可能不是你期望的。
如果你希望Solr既执行分析(用于搜索)又在完整的字面字符串上进行分面,请在Schema中使用copyField
指令创建字段的两个版本:一个Text类型和一个String类型。Text字段如果用于搜索但不分面,应该有indexed="true" docValues="false"
,String字段如果用于分面但不搜索,应该有indexed="false" docValues="true"
。
除非另有说明,下面所有参数都可以使用语法f.<fieldname>.facet.<parameter>
在每个字段的基础上指定。
facet.field
必需性 | 默认值 |
---|---|
可选 | 无 |
标识应该被视为分面的字段。它会遍历字段中的每个词并使用该词作为约束生成分面计数。此参数可以在查询中指定多次以选择多个分面字段。
重要: 如果你没有将此参数设置为模式中的至少一个字段,本节描述的其他参数都不会生效。
facet.prefix
必需性 | 默认值 |
---|---|
可选 | 无 |
将分面的词限制为以给定字符串前缀开头的词。这不会以任何方式限制查询,只限制响应查询时返回的分面。
facet.contains
必需性 | 默认值 |
---|---|
可选 | 无 |
将分面的词限制为包含给定子字符串的词。这不会以任何方式限制查询,只限制响应查询时返回的分面。
facet.contains.ignoreCase
必需性 | 默认值 |
---|---|
可选 | 无 |
如果设为true
,在匹配facet.contains
子字符串与候选分面词时忽略大小写。
facet.matches
必需性 | 默认值 |
---|---|
可选 | 无 |
只返回匹配此正则表达式的词的分面桶。
facet.sort
必需性 | 默认值 |
---|---|
可选 | 无 |
分面字段词的排序。有两个选项:
count
:按最高计数优先返回词index
:按词典顺序返回词。对于ASCII范围内的词,这将是字母顺序
如果facet.limit
大于0,默认是count
,否则默认是index
。
facet.limit
必需性 | 默认值 |
---|---|
可选 | 100 |
返回的分面计数数量。负值表示Solr将返回所有计数。
facet.offset
必需性 | 默认值 |
---|---|
可选 | 0 |
返回分面列表的偏移量以允许分页。
facet.mincount
必需性 | 默认值 |
---|---|
可选 | 0 |
分面字段包含在响应中所需的最小计数。如果字段的计数低于最小值,该字段的分面不会返回。
facet.missing
必需性 | 默认值 |
---|---|
可选 | false |
如果设为true
,此参数表示除了分面字段基于词的约束外,还应计算和返回所有匹配查询但在该字段上没有分面值的结果计数。
facet.method
必需性 | 默认值 |
---|---|
可选 | fc |
选择分面字段时使用的算法或方法类型。
可用方法如下:
enum
:枚举字段中的所有词,计算匹配词的文档与匹配查询的文档的集合交集。
这种方法推荐用于只有少数不同值的多值字段分面。每个文档的平均值数量不重要。
例如,对包含美国州名的字段分面,如Alabama, Alaska, ... Wyoming
,将产生五十个缓存过滤器,可以反复使用。filterCache
应该足够大以容纳所有缓存过滤器。
fc
:通过遍历匹配查询的文档并汇总每个文档中出现的词来计算分面计数。
如果字段是多值或被分词的(根据FieldType.isTokened()
),当前使用UnInvertedField
缓存实现。在缓存中查找每个文档以查看它包含哪些词/值,并为每个值递增计数。
此方法适用于字段索引值数量高但每个文档值数量低的情况。对于多值字段,使用混合方法,对匹配许多文档的词使用来自filterCache
的词过滤器。字母fc
代表字段缓存。
fcs
:用于单值字符串字段的每段字段分面。使用facet.method=fcs
启用,并使用threads
本地参数控制使用的线程数。此参数允许在快速索引变化的情况下更快地分面。
默认值是fc
(除了使用BoolField
字段类型的字段和请求facet.exists=true
时),因为当字段在索引中有许多唯一词时,它往往使用更少的内存并且更快。
facet.enum.cache.minDf
必需性 | 默认值 |
---|---|
可选 | 0 |
指示应该使用filterCache来确定该词的约束计数的最小文档频率(匹配词的文档数)。这只与facet.method=enum
分面方法一起使用。
大于零的值会减少filterCache的内存使用,但增加查询处理所需的时间。如果你在一个有很多词的字段上分面,并且希望减少内存使用,尝试将此参数设置为25
到50
之间的值,并运行一些测试。然后根据需要优化参数设置。
默认值是0
,使filterCache用于字段中的所有词。
facet.exists
必需性 | 默认值 |
---|---|
可选 | 无 |
要将分面计数限制为1,指定facet.exists=true
。此参数可以与facet.method=enum
一起使用或省略时使用。它只能在非trie字段(如字符串)上使用。它可能会在大索引和/或高基数分面值上加速分面计数。
facet.excludeTerms
必需性 | 默认值 |
---|---|
可选 | 无 |
从分面计数中删除词但保留它们在索引中。
facet.overrequest.count 和 facet.overrequest.ratio
必需性 | 默认值 |
---|---|
可选 | 见描述 |
在某些情况下,通过从每个独立分片”过度请求”所需约束数量(即facet.limit
),可以提高分布式Solr查询中选择分面”顶部”约束的准确性。在这些情况下,默认情况下会要求每个分片提供顶部10 + (1.5 * facet.limit)
约束。
根据文档在分片间的分区方式和使用的facet.limit
值,你可能发现增加或减少Solr的过度请求量是有利的。这可以通过设置facet.overrequest.count
(默认为10
)和facet.overrequest.ratio
(默认为1.5
)参数来实现。
facet.threads
必需性 | 默认值 |
---|---|
可选 | 0 |
用于加载分面中使用的底层字段的最大并行线程数。
省略此参数或指定线程计数为0
将不产生任何线程,只使用主请求线程。指定负数线程数将创建多达Integer.MAX_VALUE
个线程。
范围分面
你可以在任何支持范围查询的日期字段或数值字段上使用范围分面。这对于将一系列范围查询(作为查询分面)组合在一起特别有用,比如价格。
facet.range
必需性 | 默认值 |
---|---|
必需 | 无 |
Solr应该为其创建范围分面的字段。例如:
1 | facet.range=price&facet.range=age |
1 | facet.range=lastModified_dt |
facet.range.start
必需性 | 默认值 |
---|---|
必需 | 无 |
范围的下界。你可以使用语法f.<fieldname>.facet.range.start
在每个字段的基础上指定此参数。例如:
1 | f.price.facet.range.start=0.0&f.age.facet.range.start=10 |
1 | f.lastModified_dt.facet.range.start=NOW/DAY-30DAYS |
facet.range.end
必需性 | 默认值 |
---|---|
必需 | 无 |
范围的上界。你可以使用语法f.<fieldname>.facet.range.end
在每个字段的基础上指定此参数。
facet.range.gap
必需性 | 默认值 |
---|---|
必需 | 无 |
每个范围的跨度,表示为要添加到下界的值。对于日期字段,这应该使用DateMathParser语法表达(如facet.range.gap=%2B1DAY ... '+1DAY'
)。
你可以使用语法f.<fieldname>.facet.range.gap
在每个字段的基础上指定此参数。
其他范围分面参数
facet.range.hardend
:处理facet.range.gap
在facet.range.start
和facet.range.end
之间不能均匀分割的情况facet.range.include
:修改范围边界包含行为facet.range.other
:计算额外的范围计数facet.range.method
:选择范围分面的算法类型
透视(决策树)分面
透视分面是一个汇总工具,让你可以自动排序、计数、求和或平均存储在表中的数据。透视分面让你可以通过多个字段对文档分面来创建结果的汇总表。
facet.pivot
必需性 | 默认值 |
---|---|
可选 | 无 |
用于透视的字段。多个facet.pivot
值将在响应中创建多个”facet_pivot”部分。用逗号分隔每个字段列表。
透视分面示例
使用”bin/solr start -e techproducts
“示例,如下的查询URL将返回数据,透视分面结果在”facet_pivot”部分中找到:
1 | http://localhost:8983/solr/techproducts/select?q=*:*&facet.pivot=cat,popularity,inStock |
区间分面
区间分面是另一种支持的分面形式。这听起来类似于范围分面,但功能实际上更接近使用范围查询进行分面查询。区间分面允许你设置变量区间并计算在指定字段中具有这些区间内值的文档数量。
区间语法
区间必须以’(‘或’[‘开始,然后是开始值,然后是逗号(‘,’),结束值,最后是结束’)’或’]’。
例如:
(1,10)
-> 将包含大于1且小于10的值[1,10)
-> 将包含大于或等于1且小于10的值[1,10]
-> 将包含大于或等于1且小于或等于10的值
分面的本地参数
LocalParams语法允许覆盖全局设置。它还可以提供向其他参数值添加元数据的方法,很像XML属性。
标记和排除过滤器
你可以标记特定的过滤器并在分面时排除这些过滤器。这在进行多选分面时很有用。
考虑以下带分面的示例查询:
1 | q=mainquery&fq=status:public&fq=doctype:pdf&facet=true&facet.field=doctype |
要实现doctype的多选分面,标记直接约束doctype的过滤器,并在对doctype分面时排除这些过滤器。
1 | q=mainquery&fq=status:public&fq={!tag=dt}doctype:pdf&facet=true&facet.field={!ex=dt}doctype |
更改输出键
要更改分面命令的输出键,使用key
本地参数指定新名称。例如:
1 | facet.field={!ex=dt key=mylabel}doctype |
上面的参数设置使”doctype”字段的字段分面结果使用键”mylabel”而不是”doctype”在响应中返回。
相关主题
参见空间搜索了解按距离分面和通过分面生成热图的示例。
参见响应编写器了解使用JSON响应编写器时控制字段分面数据写出格式的json.nl
参数详情。