類似性モジュール

類似性(スコアリング/ランキングモデル)は、マッチするドキュメントがどのようにスコア付けされるかを定義します。類似性はフィールドごとに異なるため、マッピングを通じてフィールドごとに異なる類似性を定義できます。

カスタム類似性の設定は専門的な機能と見なされ、組み込みの類似性はsimilarityに記載されているように、ほとんどの場合十分です。

類似性の設定

ほとんどの既存またはカスタムの類似性には、以下に示すようにインデックス設定を介して設定できる構成オプションがあります。インデックスオプションは、インデックスを作成する際やインデックス設定を更新する際に提供できます。

Python

  1. resp = client.indices.create(
  2. index="index",
  3. settings={
  4. "index": {
  5. "similarity": {
  6. "my_similarity": {
  7. "type": "DFR",
  8. "basic_model": "g",
  9. "after_effect": "l",
  10. "normalization": "h2",
  11. "normalization.h2.c": "3.0"
  12. }
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'index',
  3. body: {
  4. settings: {
  5. index: {
  6. similarity: {
  7. my_similarity: {
  8. type: 'DFR',
  9. basic_model: 'g',
  10. after_effect: 'l',
  11. normalization: 'h2',
  12. "normalization.h2.c": '3.0'
  13. }
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.indices.create({
  2. index: "index",
  3. settings: {
  4. index: {
  5. similarity: {
  6. my_similarity: {
  7. type: "DFR",
  8. basic_model: "g",
  9. after_effect: "l",
  10. normalization: "h2",
  11. "normalization.h2.c": "3.0",
  12. },
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. PUT /index
  2. {
  3. "settings": {
  4. "index": {
  5. "similarity": {
  6. "my_similarity": {
  7. "type": "DFR",
  8. "basic_model": "g",
  9. "after_effect": "l",
  10. "normalization": "h2",
  11. "normalization.h2.c": "3.0"
  12. }
  13. }
  14. }
  15. }
  16. }

ここでは、DFR類似性を設定し、マッピングで[my_similarity]として参照できるようにします。以下の例に示します:

Python

  1. resp = client.indices.put_mapping(
  2. index="index",
  3. properties={
  4. "title": {
  5. "type": "text",
  6. "similarity": "my_similarity"
  7. }
  8. },
  9. )
  10. print(resp)

Ruby

  1. response = client.indices.put_mapping(
  2. index: 'index',
  3. body: {
  4. properties: {
  5. title: {
  6. type: 'text',
  7. similarity: 'my_similarity'
  8. }
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.indices.putMapping({
  2. index: "index",
  3. properties: {
  4. title: {
  5. type: "text",
  6. similarity: "my_similarity",
  7. },
  8. },
  9. });
  10. console.log(response);

コンソール

  1. PUT /index/_mapping
  2. {
  3. "properties" : {
  4. "title" : { "type" : "text", "similarity" : "my_similarity" }
  5. }
  6. }

利用可能な類似性

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

  1. resp = client.indices.create(
  2. index="index",
  3. settings={
  4. "number_of_shards": 1,
  5. "similarity": {
  6. "scripted_tfidf": {
  7. "type": "scripted",
  8. "script": {
  9. "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;"
  10. }
  11. }
  12. }
  13. },
  14. mappings={
  15. "properties": {
  16. "field": {
  17. "type": "text",
  18. "similarity": "scripted_tfidf"
  19. }
  20. }
  21. },
  22. )
  23. print(resp)
  24. resp1 = client.index(
  25. index="index",
  26. id="1",
  27. document={
  28. "field": "foo bar foo"
  29. },
  30. )
  31. print(resp1)
  32. resp2 = client.index(
  33. index="index",
  34. id="2",
  35. document={
  36. "field": "bar baz"
  37. },
  38. )
  39. print(resp2)
  40. resp3 = client.indices.refresh(
  41. index="index",
  42. )
  43. print(resp3)
  44. resp4 = client.search(
  45. index="index",
  46. explain=True,
  47. query={
  48. "query_string": {
  49. "query": "foo^1.7",
  50. "default_field": "field"
  51. }
  52. },
  53. )
  54. print(resp4)

Ruby

  1. response = client.indices.create(
  2. index: 'index',
  3. body: {
  4. settings: {
  5. number_of_shards: 1,
  6. similarity: {
  7. scripted_tfidf: {
  8. type: 'scripted',
  9. script: {
  10. 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;'
  11. }
  12. }
  13. }
  14. },
  15. mappings: {
  16. properties: {
  17. field: {
  18. type: 'text',
  19. similarity: 'scripted_tfidf'
  20. }
  21. }
  22. }
  23. }
  24. )
  25. puts response
  26. response = client.index(
  27. index: 'index',
  28. id: 1,
  29. body: {
  30. field: 'foo bar foo'
  31. }
  32. )
  33. puts response
  34. response = client.index(
  35. index: 'index',
  36. id: 2,
  37. body: {
  38. field: 'bar baz'
  39. }
  40. )
  41. puts response
  42. response = client.indices.refresh(
  43. index: 'index'
  44. )
  45. puts response
  46. response = client.search(
  47. index: 'index',
  48. explain: true,
  49. body: {
  50. query: {
  51. query_string: {
  52. query: 'foo^1.7',
  53. default_field: 'field'
  54. }
  55. }
  56. }
  57. )
  58. puts response

Js

  1. const response = await client.indices.create({
  2. index: "index",
  3. settings: {
  4. number_of_shards: 1,
  5. similarity: {
  6. scripted_tfidf: {
  7. type: "scripted",
  8. script: {
  9. source:
  10. "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;",
  11. },
  12. },
  13. },
  14. },
  15. mappings: {
  16. properties: {
  17. field: {
  18. type: "text",
  19. similarity: "scripted_tfidf",
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);
  25. const response1 = await client.index({
  26. index: "index",
  27. id: 1,
  28. document: {
  29. field: "foo bar foo",
  30. },
  31. });
  32. console.log(response1);
  33. const response2 = await client.index({
  34. index: "index",
  35. id: 2,
  36. document: {
  37. field: "bar baz",
  38. },
  39. });
  40. console.log(response2);
  41. const response3 = await client.indices.refresh({
  42. index: "index",
  43. });
  44. console.log(response3);
  45. const response4 = await client.search({
  46. index: "index",
  47. explain: "true",
  48. query: {
  49. query_string: {
  50. query: "foo^1.7",
  51. default_field: "field",
  52. },
  53. },
  54. });
  55. console.log(response4);

コンソール

  1. PUT /index
  2. {
  3. "settings": {
  4. "number_of_shards": 1,
  5. "similarity": {
  6. "scripted_tfidf": {
  7. "type": "scripted",
  8. "script": {
  9. "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;"
  10. }
  11. }
  12. }
  13. },
  14. "mappings": {
  15. "properties": {
  16. "field": {
  17. "type": "text",
  18. "similarity": "scripted_tfidf"
  19. }
  20. }
  21. }
  22. }
  23. PUT /index/_doc/1
  24. {
  25. "field": "foo bar foo"
  26. }
  27. PUT /index/_doc/2
  28. {
  29. "field": "bar baz"
  30. }
  31. POST /index/_refresh
  32. GET /index/_search?explain=true
  33. {
  34. "query": {
  35. "query_string": {
  36. "query": "foo^1.7",
  37. "default_field": "field"
  38. }
  39. }
  40. }

これにより、

コンソール-結果

  1. {
  2. "took": 12,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 1,
  6. "successful": 1,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": {
  12. "value": 1,
  13. "relation": "eq"
  14. },
  15. "max_score": 1.9508477,
  16. "hits": [
  17. {
  18. "_shard": "[index][0]",
  19. "_node": "OzrdjxNtQGaqs4DmioFw9A",
  20. "_index": "index",
  21. "_id": "1",
  22. "_score": 1.9508477,
  23. "_source": {
  24. "field": "foo bar foo"
  25. },
  26. "_explanation": {
  27. "value": 1.9508477,
  28. "description": "weight(field:foo in 0) [PerFieldSimilarity], result of:",
  29. "details": [
  30. {
  31. "value": 1.9508477,
  32. "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:",
  33. "details": [
  34. {
  35. "value": 1.0,
  36. "description": "weight",
  37. "details": []
  38. },
  39. {
  40. "value": 1.7,
  41. "description": "query.boost",
  42. "details": []
  43. },
  44. {
  45. "value": 2,
  46. "description": "field.docCount",
  47. "details": []
  48. },
  49. {
  50. "value": 4,
  51. "description": "field.sumDocFreq",
  52. "details": []
  53. },
  54. {
  55. "value": 5,
  56. "description": "field.sumTotalTermFreq",
  57. "details": []
  58. },
  59. {
  60. "value": 1,
  61. "description": "term.docFreq",
  62. "details": []
  63. },
  64. {
  65. "value": 2,
  66. "description": "term.totalTermFreq",
  67. "details": []
  68. },
  69. {
  70. "value": 2.0,
  71. "description": "doc.freq",
  72. "details": []
  73. },
  74. {
  75. "value": 3,
  76. "description": "doc.length",
  77. "details": []
  78. }
  79. ]
  80. }
  81. ]
  82. }
  83. }
  84. ]
  85. }
  86. }

スクリプト化された類似性は多くの柔軟性を提供しますが、満たす必要のある一連のルールがあります。これを満たさないと、Elasticsearchが静かに間違ったトップヒットを返したり、検索時に内部エラーで失敗する可能性があります:

  • 返されたスコアは正でなければなりません。
  • 他のすべての変数が等しい場合、doc.freqが増加するとスコアは減少してはなりません。
  • 他のすべての変数が等しい場合、doc.lengthが増加するとスコアは増加してはなりません。

上記のスクリプトのかなりの部分が、すべてのドキュメントに対して同じ統計に依存していることに気付いたかもしれません。weight_scriptを提供することで、上記をわずかに効率的にすることが可能で、スコアのドキュメントに依存しない部分を計算し、weight変数の下で利用可能になります。weight_scriptが提供されていない場合、weight1と等しくなります。weight_scriptは、scriptと同じ変数にアクセスできますが、docは除外されます。これは、スコアに対するドキュメントに依存しない寄与を計算することになっています。

以下の構成は、同じtf-idfスコアを提供しますが、わずかに効率的です:

Python

  1. resp = client.indices.create(
  2. index="index",
  3. settings={
  4. "number_of_shards": 1,
  5. "similarity": {
  6. "scripted_tfidf": {
  7. "type": "scripted",
  8. "weight_script": {
  9. "source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
  10. },
  11. "script": {
  12. "source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
  13. }
  14. }
  15. }
  16. },
  17. mappings={
  18. "properties": {
  19. "field": {
  20. "type": "text",
  21. "similarity": "scripted_tfidf"
  22. }
  23. }
  24. },
  25. )
  26. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'index',
  3. body: {
  4. settings: {
  5. number_of_shards: 1,
  6. similarity: {
  7. scripted_tfidf: {
  8. type: 'scripted',
  9. weight_script: {
  10. source: 'double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;'
  11. },
  12. script: {
  13. source: 'double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;'
  14. }
  15. }
  16. }
  17. },
  18. mappings: {
  19. properties: {
  20. field: {
  21. type: 'text',
  22. similarity: 'scripted_tfidf'
  23. }
  24. }
  25. }
  26. }
  27. )
  28. puts response

Js

  1. const response = await client.indices.create({
  2. index: "index",
  3. settings: {
  4. number_of_shards: 1,
  5. similarity: {
  6. scripted_tfidf: {
  7. type: "scripted",
  8. weight_script: {
  9. source:
  10. "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;",
  11. },
  12. script: {
  13. source:
  14. "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;",
  15. },
  16. },
  17. },
  18. },
  19. mappings: {
  20. properties: {
  21. field: {
  22. type: "text",
  23. similarity: "scripted_tfidf",
  24. },
  25. },
  26. },
  27. });
  28. console.log(response);

コンソール

  1. PUT /index
  2. {
  3. "settings": {
  4. "number_of_shards": 1,
  5. "similarity": {
  6. "scripted_tfidf": {
  7. "type": "scripted",
  8. "weight_script": {
  9. "source": "double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; return query.boost * idf;"
  10. },
  11. "script": {
  12. "source": "double tf = Math.sqrt(doc.freq); double norm = 1/Math.sqrt(doc.length); return weight * tf * norm;"
  13. }
  14. }
  15. }
  16. },
  17. "mappings": {
  18. "properties": {
  19. "field": {
  20. "type": "text",
  21. "similarity": "scripted_tfidf"
  22. }
  23. }
  24. }
  25. }

タイプ名: scripted

デフォルトの類似性

デフォルトでは、Elasticsearchはdefaultとして設定された類似性を使用します。

インデックスがdefault作成されるときに、すべてのフィールドのデフォルトの類似性を変更できます。

Python

  1. resp = client.indices.create(
  2. index="index",
  3. settings={
  4. "index": {
  5. "similarity": {
  6. "default": {
  7. "type": "boolean"
  8. }
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'index',
  3. body: {
  4. settings: {
  5. index: {
  6. similarity: {
  7. default: {
  8. type: 'boolean'
  9. }
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.indices.create({
  2. index: "index",
  3. settings: {
  4. index: {
  5. similarity: {
  6. default: {
  7. type: "boolean",
  8. },
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

類似性モジュール

類似性(スコアリング/ランキングモデル)は、マッチするドキュメントがどのようにスコア付けされるかを定義します。類似性はフィールドごとに異なるため、マッピングを通じてフィールドごとに異なる類似性を定義できます。

カスタム類似性の設定は専門的な機能と見なされ、組み込みの類似性はsimilarityに記載されているように、ほとんどの場合十分です。

Python

  1. resp = client.indices.close(
  2. index="index",
  3. )
  4. print(resp)
  5. resp1 = client.indices.put_settings(
  6. index="index",
  7. settings={
  8. "index": {
  9. "similarity": {
  10. "default": {
  11. "type": "boolean"
  12. }
  13. }
  14. }
  15. },
  16. )
  17. print(resp1)
  18. resp2 = client.indices.open(
  19. index="index",
  20. )
  21. print(resp2)

Ruby

  1. response = client.indices.close(
  2. index: 'index'
  3. )
  4. puts response
  5. response = client.indices.put_settings(
  6. index: 'index',
  7. body: {
  8. index: {
  9. similarity: {
  10. default: {
  11. type: 'boolean'
  12. }
  13. }
  14. }
  15. }
  16. )
  17. puts response
  18. response = client.indices.open(
  19. index: 'index'
  20. )
  21. puts response

Js

  1. const response = await client.indices.close({
  2. index: "index",
  3. });
  4. console.log(response);
  5. const response1 = await client.indices.putSettings({
  6. index: "index",
  7. settings: {
  8. index: {
  9. similarity: {
  10. default: {
  11. type: "boolean",
  12. },
  13. },
  14. },
  15. },
  16. });
  17. console.log(response1);
  18. const response2 = await client.indices.open({
  19. index: "index",
  20. });
  21. console.log(response2);

コンソール

  1. POST /index/_close
  2. PUT /index/_settings
  3. {
  4. "index": {
  5. "similarity": {
  6. "default": {
  7. "type": "boolean"
  8. }
  9. }
  10. }
  11. }
  12. POST /index/_open