JSON 分面 API
JSON 分面和分析
JSON 分面展现了与 Solr 传统分面类似的功能,但更注重可用性。它比传统分面有几个优势
-
更容易以编程方式构建复杂或嵌套的分面
-
JSON 提供的嵌套和结构使分面比传统分面 API 的扁平命名空间更容易阅读和理解。
-
对指标和分析的一流支持
-
更标准化的响应格式使客户端更容易解析和使用响应
分面搜索
分面搜索是关于聚合数据并计算有关该数据的指标。
有两种主要类型的分面
-
将数据(域)划分为多个存储段的分面
-
为给定存储段计算数据的分面(通常是指标、统计信息或分析函数)
存储段分面示例
以下是一个存储段分面的示例,它根据 cat
字段(类别缩写)将文档划分为存储段,并返回前 3 个存储段
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories" : {
"type": "terms",
"field": "cat",
"limit": 3
}
}
}'
SolrJ
final TermsFacetMap categoryFacet = new TermsFacetMap("cat").setLimit(3);
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("categories", categoryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
下面的响应向我们展示了 32 个文档匹配默认根域。12 个文档具有 cat:electronics
,4 个文档具有 cat:currency
,依此类推。
[...]
"facets":{
"count":32,
"categories":{
"buckets":[{
"val":"electronics",
"count":12},
{
"val":"currency",
"count":4},
{
"val":"memory",
"count":3},
]
}
}
统计分面示例
统计(也称为聚合
或分析
)分面除了显示查询结果本身之外,还可用于显示从查询结果中派生的信息。例如,统计分面可用于为在电子商务网站上寻找内存的用户提供背景信息。下面的示例计算平均价格(和其他统计信息),并允许用户衡量购物车中的内存条是否价格合理。
curl
curl http://localhost:8983/solr/techproducts/query -d '
q=memory&
fq=inStock:true&
json.facet={
"avg_price" : "avg(price)",
"num_suppliers" : "unique(manu_exact)",
"median_weight" : "percentile(weight,50)"
}'
SolrJ
final JsonQueryRequest request =
new JsonQueryRequest()
.setQuery("memory")
.withFilter("inStock:true")
.withStatFacet("avg_price", "avg(price)")
.withStatFacet("min_manufacturedate_dt", "min(manufacturedate_dt)")
.withStatFacet("num_suppliers", "unique(manu_exact)")
.withStatFacet("median_weight", "percentile(weight,50)");
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
对上述分面请求的响应将从匹配根域的文档(包含 "memory" 且 inStock:true 的文档)开始,然后在 facets
块中显示请求的统计信息
"facets" : {
"count" : 4,
"avg_price" : 109.9950008392334,
"num_suppliers" : 3,
"median_weight" : 352.0
}
分面类型
有 4 种不同类型的存储段分面,它们以两种不同的方式表现
-
"terms" 和 "range" 分面生成多个存储段,并将域中的每个文档分配到其中一个(或多个)存储段
-
"query" 和 "heatmap" 分面始终生成一个存储段,域中的所有文档都属于该存储段
以下详细介绍了每种分面类型。
术语分面
terms
分面根据字段中的唯一值对域进行存储段划分。
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
categories:{
"type": "terms",
"field" : "cat",
"limit" : 5
}
}
}'
SolrJ
final TermsFacetMap categoryFacet = new TermsFacetMap("cat").setLimit(5);
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("categories", categoryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
参数 | 说明 |
---|---|
|
要进行分面的字段名称。 |
|
用于分页,跳过前 N 个存储桶。默认为 0。 |
|
限制返回的存储桶数量。默认为 10。 |
|
指定如何对生成的存储桶进行排序。
|
|
在分布式搜索期间从分片内部请求的超出 当各个分片具有非常不同的顶级术语时,较大的值可以提高返回的最终“热门术语”的准确性。
|
|
如果为 |
|
在分布式搜索期间确定要精化的存储桶时,超出 当各个分片具有非常不同的顶级术语,并且当前
|
|
仅返回计数至少为该数字的存储桶。默认为 |
|
一个布尔值,指定是否应返回一个特殊的“缺失”存储桶,该存储桶由字段中没有值的文档定义。默认为 |
|
一个布尔值。如果为 |
|
布尔值。如果为 |
|
仅为以指定前缀开头的术语生成存储段。 |
|
为每个返回的存储段计算的聚合、指标或嵌套切面 |
|
此参数指示要使用的切面算法
|
|
一个可选参数,用于指定最终 |
查询切面
查询切面生成一个文档存储段,该存储段与域以及指定查询相匹配。
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"high_popularity": {
"type": "query",
"q": "popularity:[8 TO 10]"
}
}
}'
SolrJ
QueryFacetMap queryFacet = new QueryFacetMap("popularity:[8 TO 10]");
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("high_popularity", queryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
用户还可以指定子切面(“存储段”切面或指标)
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"high_popularity": {
"type": "query",
"q": "popularity:[8 TO 10]",
"facet" : {
"average_price" : "avg(price)"
}
}
}
}'
SolrJ
QueryFacetMap queryFacet =
new QueryFacetMap("popularity:[8 TO 10]").withStatSubFacet("average_price", "avg(price)");
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("high_popularity", queryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
示例响应
"high_popularity" : {
"count" : 36,
"average_price" : 36.75
}
范围切面
范围切面在日期或数字字段上生成多个存储段。
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"prices": {
"type": "range",
"field": "price",
"start": 0,
"end": 100,
"gap": 20
}
}
}'
SolrJ
RangeFacetMap rangeFacet = new RangeFacetMap("price", 0.0, 100.0, 20.0);
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("prices", rangeFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
上述范围切面的输出看起来有点像
"prices":{
"buckets":[
{
"val":0.0, // the bucket value represents the start of each range. This bucket covers 0-20
"count":5},
{
"val":20.0,
"count":0},
{
"val":40.0,
"count":0},
{
"val":60.0,
"count":1},
{
"val":80.0,
"count":1}
]
}
范围切面参数
范围切面参数名称和语义在很大程度上反映了 facet.range 查询参数样式切面。例如,此处的“start”对应于 facet.range 命令中的“facet.range.start”。
参数 | 说明 |
---|---|
field |
要从中生成范围存储段的数字字段或日期字段。 |
开始 |
范围的下限。 |
结束 |
范围的上限。 |
间隔 |
生成每个范围存储段的大小。 |
hardend |
布尔值,如果为真,则表示最后一个存储桶将以“end”结束,即使其宽度小于“gap”。如果为假,则最后一个存储桶的宽度将为“gap”,这可能会超出“end”。 |
其他 |
此参数表示,除了计算
|
include |
默认情况下,用于计算
|
切面 |
将为每个返回的存储桶计算的聚合、指标或嵌套分面 |
ranges |
任意范围列表,当指定时,计算给定范围上的分面,而不是
请参阅 任意范围 |
任意范围
任意范围由范围桶计算的 from 和 to 值组成。此范围可以用两种语法指定。
参数 | 说明 |
---|---|
from |
范围的下限。未指定时,默认为 |
to |
范围的上限。未指定时,默认为 |
inclusive_from |
一个布尔值,如果为 true,则表示包含下限 |
inclusive_to |
一个布尔值,如果为 true,则表示包含上限 |
range |
范围指定为字符串。这在语义上类似于
例如,对于范围 |
其他有范围的情况
当指定 ranges
时,会忽略 other
参数,但可以通过 ranges
实现相同的效果。
-
before
- 这相当于[*,some_val)
或仅指定to
值 -
after
- 这相当于(som_val, *]
或仅指定from
值 -
between
- 这相当于分别将start
、end
指定为from
和to
包含范围
当指定 ranges
时,会忽略 include
参数,但可以通过 ranges
实现相同的效果。lower
、upper
、outer
、edge
都可以通过组合使用 inclusive_to
和 inclusive_from
来实现。
带有 ranges
的范围分面
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"prices": {
"type": "range",
"field": "price",
"ranges": [
{
"from": 0,
"to": 20,
"inclusive_from": true,
"inclusive_to": false
},
{
"range": "[40,100)"
}
]
}
}
}'
上述范围切面的输出看起来有点像
{
"prices": {
"buckets": [
{
"val": "[0,20)",
"count": 5
},
{
"val": "[40,100)",
"count": 2
}
]
}
}
当指定 range 时,其在请求中的值用作响应中的键。在其他情况下,键使用 from 、to 、inclusive_to 和 inclusive_from 生成。目前,不支持自定义 key 。 |
热图分面
heatmap
分面为每个网格单元中具有空间数据的文档生成一个 2D 网格分面计数。
此功能主要记录在参考指南的 空间 部分。主要参数是 type
,用于指定 heatmap
,以及 field
,用于指示空间 RPT 字段。其余参数名称使用与分面.heatmap 查询参数样式分面相同的名称和语义,但没有 "facet.heatmap." 前缀。例如,此处的 geom
对应于 facet.heatmap 命令中的 facet.heatmap.geom
。
与将域划分为存储区的其他分面不同,heatmap 分面目前不支持 嵌套分面。 |
curl
curl http://localhost:8983/solr/spatialdata/query -d '
{
"query": "*:*",
"facet": {
"locations": {
"type": "heatmap",
"field": "location_srpt",
"geom": "[\"50 20\" TO \"180 90\"]",
"gridLevel": 4
}
}
}'
SolrJ
final JsonQueryRequest request =
new JsonQueryRequest()
.setQuery("*:*")
.setLimit(0)
.withFacet(
"locations",
new HeatmapFacetMap("location_srpt")
.setHeatmapFormat(HeatmapFacetMap.HeatmapFormat.INTS2D)
.setRegionQuery("[\"50 20\" TO \"180 90\"]")
.setGridLevel(4));
分面响应如下所示
{
"facets": {
"locations":{
"gridLevel":1,
"columns":6,
"rows":4,
"minX":-180.0,
"maxX":90.0,
"minY":-90.0,
"maxY":90.0,
"counts_ints2D":[[68,1270,459,5359,39456,1713],[123,10472,13620,7777,18376,6239],[88,6,3898,989,1314,255],[0,0,30,1,0,1]]
}
}
}
统计分面函数
与迄今为止讨论的所有分面不同,聚合函数(也称为分面函数、分析函数或指标)不会将数据划分为存储区。相反,它们计算域中所有文档上的某个内容。
聚合 | 示例 | 说明 |
---|---|---|
sum |
|
数值的总和 |
avg |
|
数值的平均值 |
min |
|
最小值 |
max |
|
最大值 |
missing |
|
对于给定字段或函数没有值的文档数 |
countvals |
|
给定字段或函数的值数 |
unique |
|
给定字段的唯一值数。超过 100 个值后,它不会产生准确的估计 |
uniqueBlock |
|
与上述相同,但占用空间更小,严格用于 计算块连接块数。给定字段在各个块中必须是唯一的,并且仅支持单值字符串字段,建议使用 docValues。 |
|
与上述相同,但使用给定查询的位集来聚合命中。 |
|
hll |
|
通过 hyper-log-log 算法分布式基数估计 |
百分位数 |
|
通过 t-digest 算法百分位数估计。按此指标排序时,将使用第一个列出的百分位数作为排序值。 |
平方和 |
|
字段或函数的平方和 |
方差 |
|
数字字段或函数的方差 |
标准差 |
|
字段或函数的标准差 |
相关性 |
|
一个函数,用于计算域中文档与前景集的关联性得分,相对于背景集(两者均定义为查询)。这主要用于构建语义知识图谱时。 |
诸如 avg
的数字聚合函数可以针对任何数字字段,或针对多个数字字段的嵌套函数,例如 avg(div(popularity,price))
。
请求聚合函数最常见的方式是作为包含您希望计算的表达式的简单字符串
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"filter": [
"price:[1.0 TO *]",
"popularity:[0 TO 10]"
],
"facet": {
"avg_value": "avg(div(popularity,price))"
}
}'
SolrJ
final JsonQueryRequest request =
new JsonQueryRequest()
.setQuery("*:*")
.withFilter("price:[1.0 TO *]")
.withFilter("popularity:[0 TO 10]")
.withStatFacet("min_manu_id_s", "min(manu_id_s)")
.withStatFacet("avg_value", "avg(div(popularity,price))");
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
扩展形式允许指定本地参数。这些参数可以被一些专门的聚合(例如 relatedness()
)显式使用,但也可以用作参数引用,以使聚合表达式更具可读性,而无需使用(全局)请求参数
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"filter": [
"price:[1.0 TO *]",
"popularity:[0 TO 10]"
],
"facet": {
"avg_value" : {
"type": "func",
"func": "avg(div($numer,$denom))",
"numer": "mul(popularity,3.0)",
"denom": "price"
}
}
}'
SolrJ
final Map<String, Object> expandedStatFacet = new HashMap<>();
expandedStatFacet.put("type", "func");
expandedStatFacet.put("func", "avg(div($numer,$denom))");
expandedStatFacet.put("numer", "mul(popularity,3.0)");
expandedStatFacet.put("denom", "price");
final JsonQueryRequest request =
new JsonQueryRequest()
.setQuery("*:*")
.withFilter("price:[1.0 TO *]")
.withFilter("popularity:[0 TO 10]")
.withFacet("avg_value", expandedStatFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
嵌套分面
嵌套分面或子分面允许将分面命令嵌套在将域划分为存储段(即 terms
、range
、query
)的任何分面命令下。然后,根据父分面的每个存储段中所有文档集定义的域,对这些子分面进行评估。
语法与顶级分面相同 - 只需将 facet
命令添加到父分面的分面命令块即可。从技术上讲,每个分面命令实际上都是一个子分面,因为我们从一个分面存储段开始,其域由主查询和过滤器定义。
嵌套分面示例
让我们从类别字段 cat
上一个简单的非嵌套 terms 分面开始
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "cat",
"limit": 3
}
}
}'
SolrJ
final TermsFacetMap categoryFacet = new TermsFacetMap("cat").setLimit(3);
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("categories", categoryFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
上面分面的响应将显示顶级类别以及落入每个类别存储段的文档数。嵌套分面可用于收集有关每个文档存储段的附加信息。例如,使用下面的嵌套分面,我们可以找到顶级类别以及每个类别中的领先制造商
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "cat",
"limit": 3,
"facet": {
"top_manufacturer": {
"type": "terms",
"field": "manu_id_s",
"limit": 1
}
}
}
}
}'
SolrJ
final TermsFacetMap topCategoriesFacet = new TermsFacetMap("cat").setLimit(3);
final TermsFacetMap topManufacturerFacet = new TermsFacetMap("manu_id_s").setLimit(1);
topCategoriesFacet.withSubFacet("top_manufacturers", topManufacturerFacet);
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("categories", topCategoriesFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
响应将类似于
"facets":{
"count":32,
"categories":{
"buckets":[{
"val":"electronics",
"count":12,
"top_manufacturer":{
"buckets":[{
"val":"corsair",
"count":3}]}},
{
"val":"currency",
"count":4,
"top_manufacturer":{
"buckets":[{
"val":"boa",
"count":1}]}}]}}
按嵌套函数对分面排序
字段或术语切面的默认排序按存储桶计数降序排列。我们还可以选择按每个存储桶中出现的任何切面函数升序或降序进行排序
。
curl
curl http://localhost:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories":{
"type" : "terms", // terms facet creates a bucket for each indexed term in the field
"field" : "cat",
"limit": 3,
"sort" : "avg_price desc",
"facet" : {
"avg_price" : "avg(price)",
}
}
}
}'
SolrJ
final TermsFacetMap topCategoriesFacet =
new TermsFacetMap("cat")
.setLimit(3)
.withStatSubFacet("avg_price", "avg(price)")
.setSort("avg_price desc");
final JsonQueryRequest request =
new JsonQueryRequest().setQuery("*:*").withFacet("categories", topCategoriesFacet);
QueryResponse queryResponse = request.process(solrClient, COLLECTION_NAME);
在某些情况下,所需的排序
可能是对每个存储桶计算成本很高的聚合函数。可以使用prelim_sort
选项来指定排序
的近似值,以便最初对存储桶进行排名以确定最优候选(基于limit
和overrequest
)。只有在对最优候选存储桶进行优化后,才会使用实际的排序
。
{
categories:{
type : terms,
field : cat,
refine: true,
limit: 10,
overrequest: 100,
prelim_sort: "sales_rank desc",
sort : "prod_quality desc",
facet : {
prod_quality : "avg(div(prod(rating,sales_rank),prod(num_returns,price)))"
sales_rank : "sum(sales_rank)"
}
}
}
更改域
如上所述,切面根据其文档“域”计算存储桶或统计信息。
-
默认情况下,顶级切面使用与主查询匹配的所有文档集作为其域。
-
为其父切面的每个存储桶计算嵌套“子切面”,使用包含该存储桶中所有文档的域。
除了此默认行为外,还可以拓宽、缩小或完全更改域。JSON 切面 API 支持通过其domain
属性修改域。在 JSON 切面域更改 中对此进行了更详细的讨论。
特殊统计切面函数
大多数统计切面函数(avg
、sumsq
等)允许用户对文档组执行数学计算。不过,一些函数更复杂,值得单独解释。这些将在以下部分中更详细地描述。
uniqueBlock() 和块连接计数
当集合包含 嵌套文档 时,blockChildren
和 blockParent
域更改 在搜索父文档时很有用,并且您希望针对所有受影响的子文档(或反之亦然)计算统计信息。但是,如果您只需要知道当前域中存在的所有块的计数,那么更有效的方法是uniqueBlock()
聚合函数。
假设我们有带有多个 SKU 的产品,并且我们想为每种颜色计算产品。
{
"id": "1", "type": "product", "name": "Solr T-Shirt",
"_childDocuments_": [
{ "id": "11", "type": "SKU", "color": "Red", "size": "L" },
{ "id": "12", "type": "SKU", "color": "Blue", "size": "L" },
{ "id": "13", "type": "SKU", "color": "Red", "size": "M" }
]
},
{
"id": "2", "type": "product", "name": "Solr T-Shirt",
"_childDocuments_": [
{ "id": "21", "type": "SKU", "color": "Blue", "size": "S" }
]
}
在针对一组 SKU 文档进行搜索时,我们可以要求对颜色进行分面,并使用嵌套统计来计算所有“块”(即产品)
color: {
type: terms,
field: color,
limit: -1,
facet: {
productsCount: "uniqueBlock(_root_)"
// or "uniqueBlock({!v=type:product})"
}
}
并获取
color:{
buckets:[
{ val:Blue, count:2, productsCount:2 },
{ val:Red, count:2, productsCount:1 }
]
}
请注意,_root_
是 Lucene 添加到每个子文档的内部字段,用于引用父文档。聚合 uniqueBlock(_root_)
在功能上等同于 unique(_root_)
,但针对嵌套文档块结构进行了优化。建议为 uniqueBlock
计算定义 limit: -1
,如上例所示,因为 limit
参数的默认值为 10
,而 uniqueBlock
在 -1
时应该快得多。
relatedness() 和语义知识图
relatedness(…)
统计函数允许对文档集进行评分,相对于前景和背景文档集,目的是找到构成“语义知识图”的临时关系
语义知识图的核心利用了倒排索引以及互补的非倒排索引来表示节点(术语)和边(多个术语/节点的相交发布列表中的文档)。这在每对节点及其对应的边之间提供了一层间接关系,使边能够从底层语料库统计中动态生成。因此,任何节点组合都可以使边生成到任何其他节点,并进行评分以揭示节点之间的潜在关系。
语义知识图
relatedness(…)
函数用于“评分”这些关系,相对于在函数参数中指定为查询的“前景”和“背景”文档集。
与大多数聚合函数不同,relatedness(…)
函数知道它是否以及如何在 嵌套分面 中使用。它独立于其父/祖先存储桶评估定义当前存储桶的查询,并将这些文档与由前景查询(与祖先存储桶结合)定义的“前景集”相交。然后将结果与针对“背景集”(由背景查询独占定义)执行的类似相交进行比较,以查看当前存储桶与前景集之间是否存在正相关或负相关,相对于背景集。
relatedness(…) 在 allBuckets 上下文中的语义目前未定义。因此,尽管 relatedness(…) 统计数据可以针对同时指定 allBuckets:true 的分面请求指定,但 allBuckets 存储桶本身不会包含相关性计算。 |
虽然将背景集定义为 *:* 或前台查询的某个其他超集非常常见,但这不是严格要求的。relatedness(…) 函数可用于比较文档集与正交前台/背景查询的统计相关性。 |
relatedness() 选项
在使用扩展 type:func
语法指定 relatedness()
聚合时,可以使用可选的 min_popularity
(浮点数)选项来指定 foreground_popularity
和 background_popularity
值的下限,必须满足此下限,relatedness
得分才有效——如果未满足此 min_popularity
,则 relatedness
得分将为 -Infinity
。
用于计算 relatedness()
域相关性的默认实现取决于要计算的面向类型。通用域相关性按术语计算,方法是通过选择性地为每个存储桶关联查询检索 DocSet(咨询 filterCache
)并计算 DocSet 与“前台”和“背景”集的交集。对于术语面向(尤其是在高基数字段上),此方法可能导致 filterCache
抖动;因此,relatedness()
在术语面向上的默认值尽可能采用一种方法,该方法直接在所有多个域上收集面向计数,一次扫描(从不接触 filterCache
)。可以通过将扩展 type:func
语法 sweep_collection
选项设置为 true
(默认值)或 false
(禁用扫描收集)来显式控制此“一次扫描”收集。
禁用 relatedness() 统计信息在低基数字段上的扫描收集可能会产生性能优势,前提是 filterCache 足够大,可以容纳关联字段中每个值的条目,而不会对预期使用模式造成抖动。一个合理的启发式方法是,基数小于 1,000 的字段可能会受益于禁用扫描。此启发式不会用于确定默认行为,特别是由于非扫描收集很容易导致 filterCache 抖动,从而对系统范围产生不利影响。 |
{ "type": "func",
"func": "relatedness($fore,$back)",
"min_popularity": 0.001,
}
当对 relatedness()
使用降序排序,并且前台和背景查询不相交时,这可能特别有用,以确保“顶部存储桶”都与这两个集合相关。
在 |
语义知识图示例
curl -sS -X POST 'http://localhost:8983/solr/gettingstarted/update?commit=true' -d '[
{"id":"01",age:15,"state":"AZ","hobbies":["soccer","painting","cycling"]},
{"id":"02",age:22,"state":"AZ","hobbies":["swimming","darts","cycling"]},
{"id":"03",age:27,"state":"AZ","hobbies":["swimming","frisbee","painting"]},
{"id":"04",age:33,"state":"AZ","hobbies":["darts"]},
{"id":"05",age:42,"state":"AZ","hobbies":["swimming","golf","painting"]},
{"id":"06",age:54,"state":"AZ","hobbies":["swimming","golf"]},
{"id":"07",age:67,"state":"AZ","hobbies":["golf","painting"]},
{"id":"08",age:71,"state":"AZ","hobbies":["painting"]},
{"id":"09",age:14,"state":"CO","hobbies":["soccer","frisbee","skiing","swimming","skating"]},
{"id":"10",age:23,"state":"CO","hobbies":["skiing","darts","cycling","swimming"]},
{"id":"11",age:26,"state":"CO","hobbies":["skiing","golf"]},
{"id":"12",age:35,"state":"CO","hobbies":["golf","frisbee","painting","skiing"]},
{"id":"13",age:47,"state":"CO","hobbies":["skiing","darts","painting","skating"]},
{"id":"14",age:51,"state":"CO","hobbies":["skiing","golf"]},
{"id":"15",age:64,"state":"CO","hobbies":["skating","cycling"]},
{"id":"16",age:73,"state":"CO","hobbies":["painting"]},
]'
curl -sS -X POST http://localhost:8983/solr/gettingstarted/query -d 'rows=0&q=*:*
&back=*:* (1)
&fore=age:[35 TO *] (2)
&json.facet={
hobby : {
type : terms,
field : hobbies,
limit : 5,
sort : { r1: desc }, (3)
facet : {
r1 : "relatedness($fore,$back)", (4)
location : {
type : terms,
field : state,
limit : 2,
sort : { r2: desc }, (3)
facet : {
r2 : "relatedness($fore,$back)" (4)
}
}
}
}
}'
1 | 使用整个集合作为我们的“背景集” |
2 | 使用查询“age >= 35”来定义我们的(初始)“前台集” |
3 | 对于顶级 hobbies 切面和 state 上的子切面,我们将在 relatedness(…) 值上进行排序 |
4 | 在对 relatedness(…) 函数的两次调用中,我们使用 参数变量 来引用先前定义的 fore 和 back 查询。 |
"facets":{
"count":16,
"hobby":{
"buckets":[{
"val":"golf",
"count":6, (1)
"r1":{
"relatedness":0.01225,
"foreground_popularity":0.3125, (2)
"background_popularity":0.375}, (3)
"location":{
"buckets":[{
"val":"az",
"count":3,
"r2":{
"relatedness":0.00496, (4)
"foreground_popularity":0.1875, (6)
"background_popularity":0.5}}, (7)
{
"val":"co",
"count":3,
"r2":{
"relatedness":-0.00496, (5)
"foreground_popularity":0.125,
"background_popularity":0.5}}]}},
{
"val":"painting",
"count":8, (1)
"r1":{
"relatedness":0.01097,
"foreground_popularity":0.375,
"background_popularity":0.5},
"location":{
"buckets":[{
...
1 | 尽管 hobbies:golf 的总切面 count 低于 hobbies:painting ,但它具有更高的 relatedness 分数,表明相对于背景集(整个集合),高尔夫与我们的前景集(35 岁以上的人)的相关性更强,而不是绘画。 |
2 | 匹配 age:[35 TO *] 和 hobbies:golf 的文档数量是背景集中文档总数的 31.25% |
3 | 背景集中 37.5% 的文档匹配 hobbies:golf |
4 | 与背景集相比,亚利桑那州 (AZ) 与嵌套前景集(35 岁以上打高尔夫的人)具有正相关性相关性——即,“亚利桑那州的人在统计上比全国更可能是‘35 岁以上的高尔夫球手’”。 |
5 | 科罗拉多州 (CO) 与嵌套前景集呈负相关性——即,“科罗拉多州的人在统计上不太可能是‘35 岁以上的高尔夫球手’,而不是全国”。 |
6 | 匹配 age:[35 TO *] 和 hobbies:golf 和 state:AZ 的文档数量是背景集中文档总数的 18.75% |
7 | 背景集中 50% 的文档匹配 state:AZ |