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 個文件符合預設根網域。十二個文件具有 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。 |
|
指定如何排序產生的儲存區。
|
|
在分散式搜尋期間,從分片內部請求的 bucket 數量超出 當個別分片具有非常不同的熱門詞彙時,較大的值可以提高最終傳回的「熱門詞彙」的準確性。 預設值 |
|
如果為 |
|
在分散式搜尋期間,確定要精煉哪些 bucket 時,內部要考慮的 bucket 數量超出 當個別分片具有非常不同的熱門詞彙時,較大的值可以提高最終傳回的「熱門詞彙」的準確性,並且目前的 預設值 |
|
僅傳回計數至少為此數字的 bucket。預設值為 |
|
一個布林值,指定是否應傳回特殊的「missing」bucket,該 bucket 由欄位中沒有值的文件定義。預設值為 |
|
一個布林值。如果為 |
|
一個布林值。如果為 |
|
僅針對以指定前置詞開頭的詞彙產生 bucket。 |
|
將為每個傳回的 bucket 計算的聚合、指標或巢狀 facet |
|
此參數指示要使用的 facet 演算法
|
|
一個可選參數,用於指定在初始收集熱門 bucket 期間使用的最終 |
查詢 Facet
查詢 facet 會產生一個單一 bucket,其中包含符合網域以及指定查詢的文件。
-
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);
使用者也可以指定子 facet (「分組」facet 或指標)
-
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
}
範圍 Facet
範圍 facet 會在日期或數值欄位上產生多個 bucket。
-
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);
上面範圍 facet 的輸出看起來會有點像
"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 參數
範圍 facet 參數名稱和語意在很大程度上反映了 facet.range 查詢參數樣式的 facet。例如,此處的「start」對應於 facet.range 命令中的「facet.range.start」。
參數 | 描述 |
---|---|
field |
要從中產生範圍 bucket 的數值欄位或日期欄位。 |
start |
範圍的下限。 |
end |
範圍的上限。 |
gap |
產生的每個範圍 bucket 的大小。 |
hardend |
一個布林值,如果為 true,則表示最後一個 bucket 將以「end」結尾,即使其寬度小於「gap」。如果為 false,則最後一個 bucket 的寬度將為「gap」,這可能會超出「end」。 |
other |
此參數表示,除了
|
include |
依預設,用於計算
|
facet |
將為每個傳回的 bucket 計算的聚合、指標或巢狀 facet |
ranges |
指定時,任意範圍列表會計算給定範圍而非
請參閱 任意範圍 |
任意範圍
任意範圍由 from 和 to 值組成,在這些值上計算範圍 bucket。此範圍可以用兩種語法指定。
參數 | 描述 |
---|---|
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
實現相同的行為。可以使用 inclusive_to
和 inclusive_from
的組合來實現 lower
、upper
、outer
、edge
。
具有 ranges
的範圍 facet
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)"
}
]
}
}
}'
上面範圍 facet 的輸出看起來會有點像
{
"prices": {
"buckets": [
{
"val": "[0,20)",
"count": 5
},
{
"val": "[40,100)",
"count": 2
}
]
}
}
指定 range 時,請求中的值將用作回應中的索引鍵。在其他情況下,索引鍵是使用 from 、to 、inclusive_to 和 inclusive_from 產生的。目前,不支援自訂 key 。 |
熱圖 Facet
heatmap
facet 會產生一個 2D 網格,其中包含在每個網格單元格中具有空間資料的文件的 facet 計數。
此功能主要記錄在參考指南的空間部分中。關鍵參數是 type
以指定 heatmap
,以及 field
以指示空間 RPT 欄位。其餘的參數名稱使用相同的名稱和語意,反映了 facet.heatmap 查詢參數樣式的 facet,儘管沒有 "facet.heatmap." 前置詞。例如,此處的 geom
對應於 facet.heatmap 命令中的 facet.heatmap.geom
。
與將網域分割成 bucket 的其他 facet 不同,heatmap facet 目前不支援巢狀 Facet。 |
-
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));
而 facet 回應將如下所示
{
"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]]
}
}
}
統計 Facet 函數
與到目前為止討論的所有 facet 不同,聚合函數 (也稱為facet 函數、分析函數或指標) 不會將資料分割成 bucket。相反地,它們會計算網域中所有文件的內容。
聚合 | 範例 | 描述 |
---|---|---|
sum |
|
數值的總和 |
avg |
|
數值的平均值 |
min |
|
最小值 |
max |
|
最大值 |
missing |
|
對於給定欄位或函數沒有值的文件數量 |
countvals |
|
給定欄位或函數的值數量 |
unique |
|
給定欄位的唯一值數量。超過 100 個值時,會產生不精確的估計 |
uniqueBlock |
|
與上述相同,但佔用空間較小,嚴格用於計算區塊聯結區塊的數量。給定的欄位在區塊中必須是唯一的,且僅支援單值字串欄位,建議使用 docValues。 |
|
與上述相同,但使用給定查詢的位元組集來聚合命中次數。 |
|
hll |
|
透過超記錄記錄演算法分散式基數估計 |
percentile |
|
透過 t-digest 演算法的百分位數估計值。依此指標排序時,會使用列出的第一個百分位數作為排序值。 |
sumsq |
|
欄位或函數的平方總和 |
variance |
|
數值欄位或函數的變異數 |
stddev |
|
欄位或函數的標準差 |
relatedness |
|
一個函數,用於計算網域中文件相對於背景集的前景集 (兩者都定義為查詢) 的相關性分數。這主要用於建置語意知識圖譜。 |
諸如 avg
的數值聚合函數可以是任何數值欄位,也可以是多個數值欄位的巢狀函數,例如 avg(div(人氣,價格))
。
要求聚合函數最常見的方法是使用包含您希望計算的運算式的簡單字串
-
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
指令添加到父分面的分面指令區塊中。從技術上講,每個分面指令實際上都是一個子分面,因為我們從一個由主查詢和過濾器定義領域的單一分面桶開始。
巢狀分面範例
我們先從一個簡單的非巢狀詞項分面(針對類別欄位 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}]}}]}}
依巢狀函數排序分面
欄位或詞項分面的預設排序方式是依桶計數降序排列。我們可以選擇依每個桶中出現的任何分面函數,以升序或降序方式進行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() 和區塊聯接計數
當集合包含巢狀文件時,在搜尋父文件並希望針對所有受影響的子文件(反之亦然)計算統計數據時,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(…)
統計函數允許根據前景和背景文件集對文件集進行評分,目的是找到構成「語義知識圖」的特定關係。
從本質上講,語義知識圖利用倒排索引和互補的反向索引來表示節點(詞項)和邊(多個詞項/節點的相交 postings list 中的文件)。這在每對節點及其對應的邊之間提供了一個間接層,使邊可以從底層語料庫統計數據中動態實現。因此,任何節點組合都可以與任何其他節點的邊實體化並進行評分,以揭示節點之間的潛在關係。
語義知識圖
relatedness(…)
函數用於相對於在函數參數中指定為查詢的「前景」和「背景」文件集對這些關係進行「評分」。
與大多數聚合函數不同,relatedness(…)
函數知道它是否以及如何在巢狀分面中使用。它獨立於其父/祖先桶評估定義當前桶的查詢,並將這些文檔與「前景集」相交,前景集由前景查詢與祖先桶組合定義。然後將結果與針對「背景集」(完全由背景查詢定義)完成的類似交集進行比較,以查看當前桶與前景集之間是否存在相對於背景集的正相關或負相關。
目前未定義 allBuckets 上下文中 relatedness(…) 的語義。因此,儘管可以為同時指定 allBuckets:true 的分面請求指定 relatedness(…) 統計資料,但 allBuckets 桶本身不包含相關性計算。 |
雖然將背景集定義為 *:* 或前景查詢的其他超集非常常見,但並非嚴格要求。relatedness(…) 函數可以用於比較多組文檔與正交前景/背景查詢的統計相關性。 |
relatedness() 選項
當使用擴展的 type:func
語法來指定 relatedness()
聚合時,可以使用可選的 min_popularity
(浮點數) 選項來指定 foreground_popularity
和 background_popularity
值的下限,必須滿足該下限,相關性分數才是有效的——如果未滿足此 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 。 |