JSON Facet API
JSON ファセッティングと分析
JSON ファセッティングは、Solr の従来のファセッティングと同様の機能を提供しますが、使いやすさを重視しています。従来のファセッティングよりもいくつかの利点があります。
-
複雑またはネストされたファセットのプログラマチックな構築が容易
-
JSON によって提供されるネストと構造により、ファセットは従来のファセッティング API のフラットな名前空間よりも読みやすく理解しやすくなります。
-
メトリクスと分析のファーストクラスサポート
-
より標準化されたレスポンス形式により、クライアントがレスポンスを解析して使用しやすくなります。
ファセット検索
ファセット検索とは、データを収集し、そのデータに関するメトリクスを計算することです。
ファセットには主に 2 つのタイプがあります。
-
データを複数の**バケット**に分割または分類するファセット(ドメイン)
-
特定のバケット(通常はメトリクス、統計、または分析関数)に対してデータを計算するファセット
バケット化ファセットの例
これは、cat
フィールド(カテゴリの略)に基づいてドキュメントをバケットに分割し、上位 3 つのバケットを返すバケット化ファセットの例です。
curl
curl https://127.0.0.1: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},
]
}
}
統計ファセットの例
統計(aggregation
またはanalytic
とも呼ばれる)ファセットは、クエリ結果自体に加えて、クエリ結果から導き出された情報を表示するのに役立ちます。たとえば、統計ファセットは、メモリを探しているeコマースサイトのユーザーにコンテキストを提供するために使用できます。以下の例では、平均価格(およびその他の統計)を計算し、ユーザーがカート内のメモリスティックが適切な価格であるかどうかを判断できるようにします。
curl
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)"
}'
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);
上記のファセットリクエストへのレスポンスは、ルートドメインに一致するドキュメント(`inStock:true` を持つ "memory" を含むドキュメント)で始まり、facets
ブロック内に要求された統計が続きます。
"facets" : {
"count" : 4,
"avg_price" : 109.9950008392334,
"num_suppliers" : 3,
"median_weight" : 352.0
}
ファセットの種類
バケット化ファセットには 4 つの異なるタイプがあり、2 つの異なる方法で動作します。
-
"terms" と "range" ファセットは複数のバケットを生成し、ドメイン内の各ドキュメントをこれらのバケットの 1 つ(または複数)に割り当てます。
-
"query" と "heatmap" ファセットは常に単一のバケットを生成し、ドメイン内のすべてのドキュメントがそれに属します。
これらの各ファセットタイプについては、以下で詳しく説明します。
Terms ファセット
terms
ファセットは、フィールドの一意の値に基づいてドメインをバケット化します。
curl
curl https://127.0.0.1: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 https://127.0.0.1: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 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)"
}
}
}
}'
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 https://127.0.0.1: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 |
範囲バケットを生成する数値フィールドまたは日付フィールド。 |
start(開始) |
範囲の下限。 |
end(終了) |
範囲の上限。 |
gap(間隔) |
生成される各範囲バケットのサイズ。 |
hardend(ハードエンド) |
ブール値。true の場合、最後のバケットは「gap」よりも狭くても「end」で終了します。false の場合、最後のバケットは「gap」の幅になり、「end」を超える可能性があります。 |
other(その他) |
このパラメータは、
|
include(含む) |
デフォルトでは、
|
facet(ファセット) |
返される各バケットに対して計算される集計、メトリック、またはネストされたファセット。 |
ranges(範囲) |
任意の範囲のリスト。指定されている場合、
任意の範囲を参照してください。 |
任意の範囲
任意の範囲は、範囲バケットが計算されるfrom値とto値で構成されます。この範囲は2つの構文で指定できます。
パラメータ | 説明 |
---|---|
from(開始) |
範囲の下限。指定されていない場合は |
to(終了) |
範囲の上限。指定されていない場合は |
inclusive_from(開始値を含む) |
ブール値。true の場合、下限 |
inclusive_to(終了値を含む) |
ブール値。true の場合、上限 |
range(範囲) |
範囲は文字列として指定されます。これは
たとえば、範囲 |
ranges を使用した other
ranges
が指定されている場合、other
パラメータは無視されますが、ranges
を使用して同じ動作を実現する方法があります。
-
before
- これは[*,some_val)
または単にto
値を指定することと同等です。 -
after
- これは(som_val, *]
または単にfrom
値を指定することと同等です。 -
between
- これはそれぞれfrom
とto
としてstart
、end
を指定することと同等です。
ranges を使用した 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グリッドを生成します。
この機能は、主にリファレンスガイドの空間セクションで説明されています。主要なパラメータは、heatmap
を指定するtype
と、空間RPTフィールドを示すfield
です。残りのパラメータ名は、"facet.heatmap."プレフィックスがないものの、facet.heatmap クエリパラメータスタイルのファセッティングを反映した同じ名前とセマンティクスを使用します。たとえば、ここのgeom
は、facet.heatmap コマンドのfacet.heatmap.geom
に対応します。
ドメインをバケットに分割する他のファセットとは異なり、heatmap ファセットは現在ネストされたファセットをサポートしていません。 |
curl
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
}
}
}'
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(ハイパーログログ) |
|
ハイパーログログアルゴリズムによる分散カーディナリティ推定 |
percentile(パーセンタイル) |
|
t-digest アルゴリズムによるパーセンタイル推定。このメトリックでソートする場合、リストされている最初のパーセンタイルがソート値として使用されます。 |
sumsq(二乗和) |
|
フィールドまたは関数の二乗の合計 |
variance(分散) |
|
数値フィールドまたは関数の分散 |
stddev(標準偏差) |
|
フィールドまたは関数の標準偏差 |
relatedness(関連性) |
|
ドメイン内の文書とフォアグラウンド集合との関連性スコアを、バックグラウンド集合(両方ともクエリとして定義)を基準に計算する関数です。これは主にセマンティックナレッジグラフを構築する場合に使用されます。 |
avg
などの数値集計関数は、任意の数値フィールド、またはavg(div(popularity,price))
などの複数の数値フィールドのネストされた関数に対して使用できます。
集計関数を要求する最も一般的な方法は、計算したい式を含む単純な文字列として指定することです。
curl
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))"
}
}'
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 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"
}
}
}'
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 https://127.0.0.1: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 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
}
}
}
}
}'
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}]}}]}}
ネストされた関数によるファセットのソート
フィールドまたはtermsファセットのデフォルトのソートは、バケットカウントの降順です。オプションで、各バケットに表示される任意のファセット関数で昇順または降順にsort
できます。
curl
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)",
}
}
}
}'
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);
場合によっては、必要な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(…)
統計関数は、「セマンティックナレッジグラフ」を構成するアドホックな関係を見つける目的で、文書の集合をフォアグラウンドとバックグラウンドの文書集合を基準にスコア付けすることを可能にします。
セマンティックナレッジグラフの中心は、逆インデックスと相補的な非逆インデックスを活用して、ノード(用語)とエッジ(複数の用語/ノードの交差する投稿リスト内の文書)を表すことです。これにより、各ノードのペアとその対応するエッジの間に間接参照レイヤーが提供され、エッジが基礎となるコーパス統計から動的にマテリアライズすることが可能になります。その結果、ノードの任意の組み合わせで、他のノードへのエッジがマテリアライズされ、スコア付けされて、ノード間の潜在的な関係を明らかにすることができます。
セマンティックナレッジグラフ
relatedness(…)
関数は、関数パラメータでクエリとして指定された「フォアグラウンド」と「バックグラウンド」の文書集合を基準に、これらの関係を「スコア付け」するために使用されます。
ほとんどの集計関数とは異なり、relatedness(…)
関数は、ネストされたファセットでどのように使用されているかを認識しています。これは、現在のバケットを定義するクエリを親/祖先バケットとは独立して評価し、フォアグラウンドクエリによって定義された「フォアグラウンド集合」と祖先バケットを組み合わせたものと、それらの文書を交差させます。次に、その結果をバックグラウンドクエリによって排他的に定義された「バックグラウンド集合」に対して行われた同様の交差と比較して、バックグラウンド集合を基準に、現在のバケットとフォアグラウンド集合の間に正の相関または負の相関があるかどうかを確認します。
allBuckets コンテキストでのrelatedness(…) のセマンティクスは現在未定義です。したがって、allBuckets:true も指定するファセットリクエストに対してrelatedness(…) 統計を指定することはできますが、allBuckets バケット自体には関連性計算が含まれません。 |
バックグラウンド集合を*:* またはフォアグラウンドクエリの他のスーパーセットとして定義することが非常に一般的ですが、厳密に必須ではありません。relatedness(…) 関数は、直交するフォアグラウンド/バックグラウンドクエリに対する文書集合の統計的関連性を比較するために使用できます。 |
relatedness()オプション
relatedness()
集計を指定するために拡張type:func
構文を使用する場合、オプションのmin_popularity
(浮動小数点数)オプションを使用して、relatedness
スコアが有効になるために満たす必要があるforeground_popularity
とbackground_popularity
値の下限を指定できます。このmin_popularity
が満たされない場合、relatedness
スコアは-Infinity
になります。
relatedness()
ドメイン相関を計算するためのデフォルトの実装は、計算されるファセットの種類によって異なります。一般的なドメイン相関は、各バケット関連クエリに対してDocSetを選択的に取得し(filterCache
を参照)、"フォアグラウンド"と"バックグラウンド"の集合とのDocSetの交差を計算することによって、用語ごとに計算されます。termsファセット(特に高カーディナリティフィールド上)では、このアプローチはfilterCache
の激しい処理につながる可能性があります。したがって、termsファセット上の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 '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 に一致します。 |