JSON 分面 API
JSON 分面和分析
JSON 分面公开了与 Solr 传统分面类似的功能,但更强调可用性。它比传统分面有几个优点
-
更易于以编程方式构建复杂或嵌套的分面
-
JSON 提供的嵌套和结构使分面比传统分面 API 的扁平命名空间更易于阅读和理解。
-
对指标和分析的一流支持
-
更标准化的响应格式使客户端更容易解析和使用响应
分面搜索
分面搜索是关于聚合数据并计算有关该数据的指标。
主要有两种类型的分面
-
将数据(域)划分为多个桶的分面,用于分区或分类
-
计算给定桶的数据的分面(通常是指标、统计信息或分析函数)
桶分面示例
这是一个桶分面的示例,它根据 cat
字段(类别的缩写)将文档划分为桶,并返回前 3 个桶
-
curl
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories" : {
"type": "terms",
"field": "cat",
"limit": 3
}
}
}'
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
-
SolrJ
curl https://127.0.0.1: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)"
}'
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
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
categories:{
"type": "terms",
"field" : "cat",
"limit" : 5
}
}
}'
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
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"high_popularity": {
"type": "query",
"q": "popularity:[8 TO 10]"
}
}
}'
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
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"high_popularity": {
"type": "query",
"q": "popularity:[8 TO 10]",
"facet" : {
"average_price" : "avg(price)"
}
}
}
}'
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
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"prices": {
"type": "range",
"field": "price",
"start": 0,
"end": 100,
"gap": 20
}
}
}'
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 |
用于生成范围桶的数字字段或日期字段。 |
start |
范围的下限。 |
end |
范围的上限。 |
gap |
生成的每个范围桶的大小。 |
hardend |
一个布尔值,如果为 true,则表示最后一个桶将以“end”结尾,即使它小于“gap”的宽度。 如果为 false,则最后一个桶将为“gap”的宽度,这可能会延伸超过“end”。 |
other |
此参数指示除了计算
|
include |
默认情况下,用于计算
|
facet |
将为每个返回的桶计算的聚合、度量或嵌套分面 |
ranges |
当指定时,任意范围列表会在给定范围而不是
参考任意范围 |
任意范围
任意范围由计算范围桶的 from 和 to 值组成。 此范围可以使用两种语法指定。
参数 | 描述 |
---|---|
from |
范围的下限。 如果未指定,则默认为 |
to |
范围的上限。 如果未指定,则默认为 |
inclusive_from |
一个布尔值,如果为 true,则表示包含下限 |
inclusive_to |
一个布尔值,如果为 true,则表示包含上限 |
range |
范围指定为字符串。 这在语义上类似于
例如,对于范围 |
other 与范围
当指定 ranges
时,将忽略 other
参数,但是可以通过 ranges
实现相同的行为。
-
before
- 这等效于[*,some_val)
或仅指定to
值 -
after
- 这等效于(som_val, *]
或仅指定from
值 -
between
- 这等效于将start
、end
分别指定为from
和to
include 与范围
当指定 ranges
时,将忽略 include
参数,但是可以通过 ranges
实现相同的行为。 lower
、upper
、outer
、edge
都可以使用 inclusive_to
和 inclusive_from
的组合来实现。
带有 ranges
的范围分面
curl https://127.0.0.1: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 字段。 其余的参数名称使用相同的名称和语义,反映了 facet.heatmap 查询参数样式的分面,但没有“facet.heatmap.”前缀。 例如,此处的 geom
对应于 facet.heatmap 命令中的 facet.heatmap.geom
。
与将域划分为桶的其他分面不同,heatmap 分面当前不支持嵌套分面。 |
-
curl
-
SolrJ
curl https://127.0.0.1:8983/solr/spatialdata/query -d '
{
"query": "*:*",
"facet": {
"locations": {
"type": "heatmap",
"field": "location_srpt",
"geom": "[\"50 20\" TO \"180 90\"]",
"gridLevel": 4
}
}
}'
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 |
|
与上述相同,但占用空间更小,专用于计算 Block Join 块的数量。给定字段在块之间必须是唯一的,并且只支持单值字符串字段,建议使用 docValues。 |
|
与上述相同,但使用给定查询的位集来聚合命中。 |
|
hll |
|
通过 hyper-log-log 算法进行分布式基数估计 |
percentile |
|
通过 t-digest 算法进行百分位数估计。当按此指标排序时,将使用列出的第一个百分位数作为排序值。 |
sumsq |
|
字段或函数的平方和 |
variance |
|
数值字段或函数的方差 |
stddev |
|
字段或函数的标准差 |
relatedness |
|
一个用于计算域中与前景集合相关的文档的相关性得分的函数,相对于背景集合(两者都定义为查询)。这主要用于构建语义知识图谱。 |
诸如 avg
之类的数值聚合函数可以应用于任何数值字段,或者应用于多个数值字段的嵌套函数,例如 avg(div(popularity,price))
。
请求聚合函数最常见的方式是使用一个简单的字符串,其中包含你想要计算的表达式
-
curl
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"filter": [
"price:[1.0 TO *]",
"popularity:[0 TO 10]"
],
"facet": {
"avg_value": "avg(div(popularity,price))"
}
}'
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
-
SolrJ
curl https://127.0.0.1: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"
}
}
}'
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
命令添加到父分面的分面命令块中。从技术上讲,每个分面命令实际上都是一个子分面,因为我们从一个由主查询和过滤器定义的域的单个分面桶开始。
嵌套分面示例
让我们从一个简单的非嵌套 terms 分面开始,该分面位于类别字段 cat
上
-
curl
-
SolrJ
curl https://127.0.0.1:8983/solr/techproducts/query -d '
{
"query": "*:*",
"facet": {
"categories": {
"type": "terms",
"field": "cat",
"limit": 3
}
}
}'
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
-
SolrJ
curl https://127.0.0.1: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
}
}
}
}
}'
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}]}}]}}
按嵌套函数对分面进行排序
字段或 terms 分面的默认排序是按桶计数降序排列。我们可以选择按每个桶中出现的任何分面函数进行升序或降序 sort
。
-
curl
-
SolrJ
curl https://127.0.0.1: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)",
}
}
}
}'
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);
在某些情况下,所需的 sort
可能是对于每个桶计算成本都很高的聚合函数。可以使用 prelim_sort
选项来指定 sort
的近似值,用于初始对桶进行排名,以确定顶级候选者(基于 limit
和 overrequest
)。只有在优化了顶级候选桶之后,才会使用实际的 sort
。
{
"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() 和 Block Join 计数
当一个集合包含嵌套文档时,当搜索父文档并且你想要针对所有受影响的子文档计算统计信息时(反之亦然),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 上下文中的语义当前未定义。因此,尽管可以为还指定 allBuckets:true 的分面请求指定 relatedness(…) 统计信息,但 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
(禁用扫描收集)来显式控制此“单次扫描”收集。
如果 filterCache 足够大,可以容纳相关字段中每个值的条目,而不会为预期的使用模式引起抖动,则禁用低基数字段的 relatedness() 统计信息的扫描收集可能会带来性能优势。一个合理的启发式方法是,基数小于 1,000 的字段可能会从禁用扫描中受益。此启发式方法不用于确定默认行为,尤其是因为非扫描收集很容易导致 filterCache 抖动,从而产生系统范围的不利影响。 |
{
"type": "func",
"func": "relatedness($fore,$back)",
"min_popularity": 0.001
}
当对不相交的前景和背景查询使用 relatedness()
降序排序时,这尤其有用,以确保“顶级桶”都与这两个集合相关。
通过添加 |
语义知识图谱示例
curl -sS -X POST 'https://127.0.0.1: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 https://127.0.0.1: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 。 |