類似性モジュール
類似性(スコアリング/ランキングモデル)は、マッチするドキュメントがどのようにスコア付けされるかを定義します。類似性はフィールドごとに異なるため、マッピングを通じてフィールドごとに異なる類似性を定義できます。
カスタム類似性の設定は専門的な機能と見なされ、組み込みの類似性はsimilarity
に記載されているように、ほとんどの場合十分です。
類似性の設定
ほとんどの既存またはカスタムの類似性には、以下に示すようにインデックス設定を介して設定できる構成オプションがあります。インデックスオプションは、インデックスを作成する際やインデックス設定を更新する際に提供できます。
Python
resp = client.indices.create(
index="index",
settings={
"index": {
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
}
},
)
print(resp)
Ruby
response = client.indices.create(
index: 'index',
body: {
settings: {
index: {
similarity: {
my_similarity: {
type: 'DFR',
basic_model: 'g',
after_effect: 'l',
normalization: 'h2',
"normalization.h2.c": '3.0'
}
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "index",
settings: {
index: {
similarity: {
my_similarity: {
type: "DFR",
basic_model: "g",
after_effect: "l",
normalization: "h2",
"normalization.h2.c": "3.0",
},
},
},
},
});
console.log(response);
コンソール
PUT /index
{
"settings": {
"index": {
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
}
}
}
ここでは、DFR類似性を設定し、マッピングで[my_similarity
]として参照できるようにします。以下の例に示します:
Python
resp = client.indices.put_mapping(
index="index",
properties={
"title": {
"type": "text",
"similarity": "my_similarity"
}
},
)
print(resp)
Ruby
response = client.indices.put_mapping(
index: 'index',
body: {
properties: {
title: {
type: 'text',
similarity: 'my_similarity'
}
}
}
)
puts response
Js
const response = await client.indices.putMapping({
index: "index",
properties: {
title: {
type: "text",
similarity: "my_similarity",
},
},
});
console.log(response);
コンソール
PUT /index/_mapping
{
"properties" : {
"title" : { "type" : "text", "similarity" : "my_similarity" }
}
}
利用可能な類似性
BM25類似性(デフォルト)
TF/IDFに基づく類似性で、組み込みのtf正規化があり、短いフィールド(名前など)に対してより良く機能することが期待されています。詳細については、Okapi_BM25を参照してください。この類似性には以下のオプションがあります:
k1 |
非線形の用語頻度正規化を制御します。 (飽和)。デフォルト値は 1.2 です。 |
b |
ドキュメントの長さがtf値をどの程度正規化するかを制御します。 デフォルト値は 0.75 です。 |
discount_overlaps |
重複トークン(位置インクリメントが0のトークン)がノルムを計算する際に無視されるかどうかを決定します。デフォルトではこれは真であり、重複トークンはノルムを計算する際にカウントされません。 |
タイプ名: BM25
DFR類似性
ランダムからの逸脱フレームワークを実装する類似性です。この類似性には以下のオプションがあります:
basic_model |
可能な値: g 、if 、in およびine 。 |
after_effect |
可能な値: b およびl 。 |
normalization |
可能な値: no 、h1 、h2 、h3 およびz 。 |
最初のオプションを除くすべてのオプションには正規化値が必要です。
タイプ名: DFR
DFI類似性
独立からの逸脱モデルを実装する類似性です。この類似性には以下のオプションがあります:
independence_measure |
可能な値standardized 、saturated 、chisquared 。 |
この類似性を使用する場合、良好な関連性を得るためにストップワードを削除しないことを強く推奨します。また、期待される頻度よりも少ない頻度の用語はスコアが0になりますので注意してください。
タイプ名: DFI
IB類似性。
情報に基づくモデル。このアルゴリズムは、任意の記号的分布シーケンスの情報内容がその基本要素の反復使用によって主に決定されるという概念に基づいています。書かれたテキストにおいて、この課題は異なる著者の文体を比較することに相当します。この類似性には以下のオプションがあります:
distribution |
可能な値:ll およびspl 。 |
lambda |
可能な値:df およびttf 。 |
normalization |
DFR 類似性と同じです。 |
タイプ名: IB
LM Dirichlet類似性。
LM Dirichlet類似性。この類似性には以下のオプションがあります:
mu |
デフォルトは2000 です。 |
論文のスコアリング公式は、言語モデルによって予測されたよりも少ない出現回数の用語に負のスコアを割り当てますが、これはLuceneにとって不正であるため、そのような用語はスコア0になります。
タイプ名: LMDirichlet
LM Jelinek Mercer類似性。
LM Jelinek Mercer類似性。このアルゴリズムは、テキストの重要なパターンを捉えつつ、ノイズを除外しようとします。この類似性には以下のオプションがあります:
lambda |
最適な値はコレクションとクエリの両方に依存します。最適な値は、タイトルクエリの場合は約0.1 、長いクエリの場合は0.7 です。デフォルトは0.1 です。値が0 に近づくと、より多くのクエリ用語に一致するドキュメントが、より少ない用語に一致するドキュメントよりも高くランク付けされます。 |
タイプ名: LMJelinekMercer
スクリプト化された類似性
スコアを計算する方法を指定するためにスクリプトを使用できる類似性です。たとえば、以下の例はTF-IDFを再実装する方法を示しています:
Python
resp = client.indices.create(
index="index",
settings={
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;"
}
}
}
},
mappings={
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
},
)
print(resp)
resp1 = client.index(
index="index",
id="1",
document={
"field": "foo bar foo"
},
)
print(resp1)
resp2 = client.index(
index="index",
id="2",
document={
"field": "bar baz"
},
)
print(resp2)
resp3 = client.indices.refresh(
index="index",
)
print(resp3)
resp4 = client.search(
index="index",
explain=True,
query={
"query_string": {
"query": "foo^1.7",
"default_field": "field"
}
},
)
print(resp4)
Ruby
response = client.indices.create(
index: 'index',
body: {
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: 'scripted',
script: {
source: 'double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;'
}
}
}
},
mappings: {
properties: {
field: {
type: 'text',
similarity: 'scripted_tfidf'
}
}
}
}
)
puts response
response = client.index(
index: 'index',
id: 1,
body: {
field: 'foo bar foo'
}
)
puts response
response = client.index(
index: 'index',
id: 2,
body: {
field: 'bar baz'
}
)
puts response
response = client.indices.refresh(
index: 'index'
)
puts response
response = client.search(
index: 'index',
explain: true,
body: {
query: {
query_string: {
query: 'foo^1.7',
default_field: 'field'
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "index",
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: "scripted",
script: {
source:
"double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;",
},
},
},
},
mappings: {
properties: {
field: {
type: "text",
similarity: "scripted_tfidf",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "index",
id: 1,
document: {
field: "foo bar foo",
},
});
console.log(response1);
const response2 = await client.index({
index: "index",
id: 2,
document: {
field: "bar baz",
},
});
console.log(response2);
const response3 = await client.indices.refresh({
index: "index",
});
console.log(response3);
const response4 = await client.search({
index: "index",
explain: "true",
query: {
query_string: {
query: "foo^1.7",
default_field: "field",
},
},
});
console.log(response4);
コンソール
PUT /index
{
"settings": {
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;"
}
}
}
},
"mappings": {
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
}
}
PUT /index/_doc/1
{
"field": "foo bar foo"
}
PUT /index/_doc/2
{
"field": "bar baz"
}
POST /index/_refresh
GET /index/_search?explain=true
{
"query": {
"query_string": {
"query": "foo^1.7",
"default_field": "field"
}
}
}
コンソール-結果
{
"took": 12,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.9508477,
"hits": [
{
"_shard": "[index][0]",
"_node": "OzrdjxNtQGaqs4DmioFw9A",
"_index": "index",
"_id": "1",
"_score": 1.9508477,
"_source": {
"field": "foo bar foo"
},
"_explanation": {
"value": 1.9508477,
"description": "weight(field:foo in 0) [PerFieldSimilarity], result of:",
"details": [
{
"value": 1.9508477,
"description": "score from ScriptedSimilarity(weightScript=[null], script=[Script{type=inline, lang='painless', idOrCode='double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;', options={}, params={}}]) computed from:",
"details": [
{
"value": 1.0,
"description": "weight",
"details": []
},
{
"value": 1.7,
"description": "query.boost",
"details": []
},
{
"value": 2,
"description": "field.docCount",
"details": []
},
{
"value": 4,
"description": "field.sumDocFreq",
"details": []
},
{
"value": 5,
"description": "field.sumTotalTermFreq",
"details": []
},
{
"value": 1,
"description": "term.docFreq",
"details": []
},
{
"value": 2,
"description": "term.totalTermFreq",
"details": []
},
{
"value": 2.0,
"description": "doc.freq",
"details": []
},
{
"value": 3,
"description": "doc.length",
"details": []
}
]
}
]
}
}
]
}
}
スクリプト化された類似性は多くの柔軟性を提供しますが、満たす必要のある一連のルールがあります。これを満たさないと、Elasticsearchが静かに間違ったトップヒットを返したり、検索時に内部エラーで失敗する可能性があります:
- 返されたスコアは正でなければなりません。
- 他のすべての変数が等しい場合、
doc.freq
が増加するとスコアは減少してはなりません。 - 他のすべての変数が等しい場合、
doc.length
が増加するとスコアは増加してはなりません。
上記のスクリプトのかなりの部分が、すべてのドキュメントに対して同じ統計に依存していることに気付いたかもしれません。weight_script
を提供することで、上記をわずかに効率的にすることが可能で、スコアのドキュメントに依存しない部分を計算し、weight
変数の下で利用可能になります。weight_script
が提供されていない場合、weight
は1
と等しくなります。weight_script
は、script
と同じ変数にアクセスできますが、doc
は除外されます。これは、スコアに対するドキュメントに依存しない寄与を計算することになっています。
以下の構成は、同じtf-idfスコアを提供しますが、わずかに効率的です:
Python
resp = client.indices.create(
index="index",
settings={
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"weight_script": {
"source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
},
"script": {
"source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
}
}
}
},
mappings={
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
},
)
print(resp)
Ruby
response = client.indices.create(
index: 'index',
body: {
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: 'scripted',
weight_script: {
source: 'double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;'
},
script: {
source: 'double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;'
}
}
}
},
mappings: {
properties: {
field: {
type: 'text',
similarity: 'scripted_tfidf'
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "index",
settings: {
number_of_shards: 1,
similarity: {
scripted_tfidf: {
type: "scripted",
weight_script: {
source:
"double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;",
},
script: {
source:
"double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;",
},
},
},
},
mappings: {
properties: {
field: {
type: "text",
similarity: "scripted_tfidf",
},
},
},
});
console.log(response);
コンソール
PUT /index
{
"settings": {
"number_of_shards": 1,
"similarity": {
"scripted_tfidf": {
"type": "scripted",
"weight_script": {
"source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
},
"script": {
"source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
}
}
}
},
"mappings": {
"properties": {
"field": {
"type": "text",
"similarity": "scripted_tfidf"
}
}
}
}
タイプ名: scripted
デフォルトの類似性
デフォルトでは、Elasticsearchはdefault
として設定された類似性を使用します。
インデックスがdefault
作成されるときに、すべてのフィールドのデフォルトの類似性を変更できます。
Python
resp = client.indices.create(
index="index",
settings={
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
},
)
print(resp)
Ruby
response = client.indices.create(
index: 'index',
body: {
settings: {
index: {
similarity: {
default: {
type: 'boolean'
}
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "index",
settings: {
index: {
similarity: {
default: {
type: "boolean",
},
},
},
},
});
console.log(response);
類似性モジュール
類似性(スコアリング/ランキングモデル)は、マッチするドキュメントがどのようにスコア付けされるかを定義します。類似性はフィールドごとに異なるため、マッピングを通じてフィールドごとに異なる類似性を定義できます。
カスタム類似性の設定は専門的な機能と見なされ、組み込みの類似性はsimilarity
に記載されているように、ほとんどの場合十分です。
Python
resp = client.indices.close(
index="index",
)
print(resp)
resp1 = client.indices.put_settings(
index="index",
settings={
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
},
)
print(resp1)
resp2 = client.indices.open(
index="index",
)
print(resp2)
Ruby
response = client.indices.close(
index: 'index'
)
puts response
response = client.indices.put_settings(
index: 'index',
body: {
index: {
similarity: {
default: {
type: 'boolean'
}
}
}
}
)
puts response
response = client.indices.open(
index: 'index'
)
puts response
Js
const response = await client.indices.close({
index: "index",
});
console.log(response);
const response1 = await client.indices.putSettings({
index: "index",
settings: {
index: {
similarity: {
default: {
type: "boolean",
},
},
},
},
});
console.log(response1);
const response2 = await client.indices.open({
index: "index",
});
console.log(response2);
コンソール
POST /index/_close
PUT /index/_settings
{
"index": {
"similarity": {
"default": {
"type": "boolean"
}
}
}
}
POST /index/_open