スクリプトスコアクエリ

カスタムスコアを返されたドキュメントに提供するために、スクリプトを使用します。

  1. ## 例のリクエスト
  2. 次の`````script_score`````クエリは、返された各ドキュメントに`````my-int`````フィールドの値を`````10`````で割ったスコアを割り当てます。
  3. #### Python
  4. ``````python
  5. resp = client.search(
  6. query={
  7. "script_score": {
  8. "query": {
  9. "match": {
  10. "message": "elasticsearch"
  11. }
  12. },
  13. "script": {
  14. "source": "doc['my-int'].value / 10 "
  15. }
  16. }
  17. },
  18. )
  19. print(resp)
  20. `

Ruby

  1. response = client.search(
  2. body: {
  3. query: {
  4. script_score: {
  5. query: {
  6. match: {
  7. message: 'elasticsearch'
  8. }
  9. },
  10. script: {
  11. source: "doc['my-int'].value / 10 "
  12. }
  13. }
  14. }
  15. }
  16. )
  17. puts response

Js

  1. const response = await client.search({
  2. query: {
  3. script_score: {
  4. query: {
  5. match: {
  6. message: "elasticsearch",
  7. },
  8. },
  9. script: {
  10. source: "doc['my-int'].value / 10 ",
  11. },
  12. },
  13. },
  14. });
  15. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query": {
  6. "match": { "message": "elasticsearch" }
  7. },
  8. "script": {
  9. "source": "doc['my-int'].value / 10 "
  10. }
  11. }
  12. }
  13. }

script_scoreのトップレベルパラメータ

  • query
  • (必須、クエリオブジェクト) ドキュメントを返すために使用されるクエリ。
  • script
  • (必須、スクリプトオブジェクト) queryによって返されたドキュメントのスコアを計算するために使用されるスクリプト。
    script_scoreクエリからの最終的な関連スコアは負の値にはできません。特定の検索最適化をサポートするために、Luceneはスコアが正または0であることを要求します。
  • min_score
  • (オプション、浮動小数点) この浮動小数点数よりもスコアが低いドキュメントは検索結果から除外されます。
  • boost
  • (オプション、浮動小数点) scriptによって生成されたドキュメントのスコアはboostで乗算され、最終的なドキュメントのスコアが生成されます。デフォルトは1.0です。

ノート

スクリプト内での関連スコアの使用

スクリプト内で、ドキュメントの現在の関連スコアを表す_score変数にアクセスできます。

事前定義された関数

利用可能なペインレス関数のいずれかをscriptで使用できます。また、スコアリングをカスタマイズするために次の事前定義された関数を使用できます:

これらの事前定義された関数を使用することをお勧めします。これらの関数はElasticsearchの内部メカニズムからの効率を活用します。

飽和

saturation(value,k) = value/(k + value)

Js

  1. "script" : {
  2. "source" : "saturation(doc['my-int'].value, 1)"
  3. }

シグモイド

sigmoid(value, k, a) = value^a/ (k^a + value^a)

Js

  1. "script" : {
  2. "source" : "sigmoid(doc['my-int'].value, 2, 1)"
  3. }

ランダムスコア関数

  1. `````randomScore`````関数は次の構文を持ちます:`````randomScore(<seed>, <fieldName>)`````。必須パラメータとして整数値の`````seed`````があり、オプションパラメータとして文字列値の`````fieldName`````があります。
  2. #### Js
  3. ``````js
  4. "script" : {
  5. "source" : "randomScore(100, '_seq_no')"
  6. }
  7. `
  1. #### Js
  2. ``````js
  3. "script" : {
  4. "source" : "randomScore(100)"
  5. }
  6. `

同じシャード内にあり、フィールドの値が同じドキュメントは同じスコアを取得するため、通常はシャード全体でユニークな値を持つフィールドを使用することが望ましいです。良いデフォルトの選択肢は_seq_noフィールドを使用することですが、唯一の欠点は、ドキュメントが更新されるとスコアが変わることです。なぜなら、更新操作も_seq_noフィールドの値を更新するからです。

数値フィールドの減衰関数

減衰関数についてはこちらで詳しく読むことができます。

  • double decayNumericLinear(double origin, double scale, double offset, double decay, double docValue)
  • double decayNumericExp(double origin, double scale, double offset, double decay, double docValue)
  • double decayNumericGauss(double origin, double scale, double offset, double decay, double docValue)

Js

  1. "script" : {
  2. "source" : "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['dval'].value)",
  3. "params": {
  4. "origin": 20,
  5. "scale": 10,
  6. "decay" : 0.5,
  7. "offset" : 0
  8. }
  9. }
paramsを使用すると、パラメータが変更されてもスクリプトを1回だけコンパイルできます。

地理フィールドの減衰関数

  • double decayGeoLinear(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
  • double decayGeoExp(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
  • double decayGeoGauss(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)

Js

  1. "script" : {
  2. "source" : "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
  3. "params": {
  4. "origin": "40, -70.12",
  5. "scale": "200km",
  6. "offset": "0km",
  7. "decay" : 0.2
  8. }
  9. }

日付フィールドの減衰関数

  • double decayDateLinear(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
  • double decayDateExp(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
  • double decayDateGauss(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)

Js

  1. "script" : {
  2. "source" : "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",
  3. "params": {
  4. "origin": "2008-01-01T01:00:00Z",
  5. "scale": "1h",
  6. "offset" : "0",
  7. "decay" : 0.5
  8. }
  9. }

日付の減衰関数は、デフォルト形式およびデフォルトタイムゾーンの日付に制限されています。また、nowとの計算はサポートされていません。

ベクトルフィールドの関数

ベクトルフィールドの関数script_scoreクエリを通じてアクセスできます。

高価なクエリを許可する

スクリプトスコアクエリは、search.allow_expensive_queriesがfalseに設定されている場合、実行されません。

より高速な代替手段

  1. - 一部の静的フィールドでドキュメントをブーストしたい場合は、[`````rank_feature`````](/read/elasticsearch-8-15/c374b3493be80889.md)クエリを使用します。
  2. - 日付や地理的ポイントに近いドキュメントをブーストしたい場合は、[`````distance_feature`````](/read/elasticsearch-8-15/7310ef6f3c063975.md)クエリを使用します。
  3. ### 関数スコアクエリからの移行
  4. `````script_score`````クエリを[`````function_score`````](/read/elasticsearch-8-15/516b6d3b74ec50ab.md)クエリの代わりに使用することをお勧めします。`````script_score`````クエリのシンプルさのためです。
  5. `````function_score`````クエリの次の関数を`````script_score`````クエリを使用して実装できます:
  6. - [`````script_score`````](2ffee97f686b4ace.md#script-score)
  7. - [`````weight`````](2ffee97f686b4ace.md#weight)
  8. - [`````random_score`````](2ffee97f686b4ace.md#random-score)
  9. - [`````field_value_factor`````](2ffee97f686b4ace.md#field-value-factor)
  10. - [`````decay`````関数](2ffee97f686b4ace.md#decay-functions)
  11. #### script_score
  12. Function Scoreクエリの`````script_score`````で使用したものを、Script Scoreクエリにコピーできます。ここに変更はありません。
  13. #### weight
  14. `````weight`````関数は、次のスクリプトを通じてScript Scoreクエリで実装できます:
  15. #### Js
  16. ``````js
  17. "script" : {
  18. "source" : "params.weight * _score",
  19. "params": {
  20. "weight": 2
  21. }
  22. }
  23. `

random_score

[randomScore]関数を、ランダムスコア関数で説明されているように使用します。

field_value_factor

  1. #### Js
  2. ``````js
  3. "script" : {
  4. "source" : "Math.log10(doc['field'].value * params.factor)",
  5. "params" : {
  6. "factor" : 5
  7. }
  8. }
  9. `

ドキュメントにフィールドfieldがない場合に値が欠落しているかどうかを確認するには、doc['field'].size() == 0を使用できます。たとえば、このスクリプトは、ドキュメントにフィールドfieldがない場合に値1を使用します:

Js

  1. "script" : {
  2. "source" : "Math.log10((doc['field'].size() == 0 ? 1 : doc['field'].value()) * params.factor)",
  3. "params" : {
  4. "factor" : 5
  5. }
  6. }

この表は、field_value_factor修飾子がスクリプトを通じてどのように実装できるかを示しています:

修飾子 Script Scoreでの実装
none -
log Math.log10(doc['f'].value)
log1p Math.log10(doc['f'].value + 1)
log2p Math.log10(doc['f'].value + 2)
ln Math.log(doc['f'].value)
ln1p Math.log(doc['f'].value + 1)
ln2p Math.log(doc['f'].value + 2)
square Math.pow(doc['f'].value, 2)
sqrt Math.sqrt(doc['f'].value)
reciprocal 1.0 / doc['f'].value

減衰関数

  1. ### ベクトルフィールドの関数
  2. ベクトル関数の計算中、すべての一致するドキュメントが線形スキャンされます。したがって、一致するドキュメントの数に応じてクエリ時間が線形に増加することを期待してください。このため、`````query`````パラメータで一致するドキュメントの数を制限することをお勧めします。
  3. 利用可能なベクトル関数とベクトルアクセスメソッドのリストは次のとおりです:
  4. - 1*.* [`````cosineSimilarity`````](2ffee97f686b4ace.md#vector-functions-cosine) – コサイン類似度を計算
  5. - 2*.* [`````dotProduct`````](2ffee97f686b4ace.md#vector-functions-dot-product) – ドット積を計算
  6. - 3*.* [`````l1norm`````](2ffee97f686b4ace.md#vector-functions-l1) – L1距離を計算
  7. - 4*.* [`````hamming`````](2ffee97f686b4ace.md#vector-functions-hamming) – ハミング距離を計算
  8. - 5*.* [`````l2norm`````](2ffee97f686b4ace.md#vector-functions-l2) - L2距離を計算
  9. - 6*.* [`````doc[<field>].vectorValue`````](2ffee97f686b4ace.md#vector-functions-accessing-vectors) – ベクトルの値を浮動小数点の配列として返す
  10. - 7*.* [`````doc[<field>].magnitude`````](2ffee97f686b4ace.md#vector-functions-accessing-vectors) – ベクトルの大きさを返す
  11. `````cosineSimilarity`````および`````dotProduct`````関数は`````bit`````ベクトルにはサポートされていません。
  12. 密なベクトルにアクセスする推奨方法は、`````cosineSimilarity``````````dotProduct``````````l1norm`````または`````l2norm`````関数を通じてです。ただし、これらの関数はスクリプトごとに1回だけ呼び出す必要があります。たとえば、ドキュメントベクトルと複数の他のベクトルとの類似度を計算するためにループ内でこれらの関数を使用しないでください。その機能が必要な場合は、[ベクトル値に直接アクセスする](2ffee97f686b4ace.md#vector-functions-accessing-vectors)ことによってこれらの関数を再実装してください。
  13. `````dense_vector`````マッピングを持つインデックスを作成し、いくつかのドキュメントをインデックスに追加しましょう。
  14. #### Python
  15. ``````python
  16. resp = client.indices.create(
  17. index="my-index-000001",
  18. mappings={
  19. "properties": {
  20. "my_dense_vector": {
  21. "type": "dense_vector",
  22. "index": False,
  23. "dims": 3
  24. },
  25. "my_byte_dense_vector": {
  26. "type": "dense_vector",
  27. "index": False,
  28. "dims": 3,
  29. "element_type": "byte"
  30. },
  31. "status": {
  32. "type": "keyword"
  33. }
  34. }
  35. },
  36. )
  37. print(resp)
  38. resp1 = client.index(
  39. index="my-index-000001",
  40. id="1",
  41. document={
  42. "my_dense_vector": [
  43. 0.5,
  44. 10,
  45. 6
  46. ],
  47. "my_byte_dense_vector": [
  48. 0,
  49. 10,
  50. 6
  51. ],
  52. "status": "published"
  53. },
  54. )
  55. print(resp1)
  56. resp2 = client.index(
  57. index="my-index-000001",
  58. id="2",
  59. document={
  60. "my_dense_vector": [
  61. -0.5,
  62. 10,
  63. 10
  64. ],
  65. "my_byte_dense_vector": [
  66. 0,
  67. 10,
  68. 10
  69. ],
  70. "status": "published"
  71. },
  72. )
  73. print(resp2)
  74. resp3 = client.indices.refresh(
  75. index="my-index-000001",
  76. )
  77. print(resp3)
  78. `

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. my_dense_vector: {
  6. type: "dense_vector",
  7. index: false,
  8. dims: 3,
  9. },
  10. my_byte_dense_vector: {
  11. type: "dense_vector",
  12. index: false,
  13. dims: 3,
  14. element_type: "byte",
  15. },
  16. status: {
  17. type: "keyword",
  18. },
  19. },
  20. },
  21. });
  22. console.log(response);
  23. const response1 = await client.index({
  24. index: "my-index-000001",
  25. id: 1,
  26. document: {
  27. my_dense_vector: [0.5, 10, 6],
  28. my_byte_dense_vector: [0, 10, 6],
  29. status: "published",
  30. },
  31. });
  32. console.log(response1);
  33. const response2 = await client.index({
  34. index: "my-index-000001",
  35. id: 2,
  36. document: {
  37. my_dense_vector: [-0.5, 10, 10],
  38. my_byte_dense_vector: [0, 10, 10],
  39. status: "published",
  40. },
  41. });
  42. console.log(response2);
  43. const response3 = await client.indices.refresh({
  44. index: "my-index-000001",
  45. });
  46. console.log(response3);

コンソール

  1. PUT my-index-000001
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_dense_vector": {
  6. "type": "dense_vector",
  7. "index": false,
  8. "dims": 3
  9. },
  10. "my_byte_dense_vector": {
  11. "type": "dense_vector",
  12. "index": false,
  13. "dims": 3,
  14. "element_type": "byte"
  15. },
  16. "status" : {
  17. "type" : "keyword"
  18. }
  19. }
  20. }
  21. }
  22. PUT my-index-000001/_doc/1
  23. {
  24. "my_dense_vector": [0.5, 10, 6],
  25. "my_byte_dense_vector": [0, 10, 6],
  26. "status" : "published"
  27. }
  28. PUT my-index-000001/_doc/2
  29. {
  30. "my_dense_vector": [-0.5, 10, 10],
  31. "my_byte_dense_vector": [0, 10, 10],
  32. "status" : "published"
  33. }
  34. POST my-index-000001/_refresh

コサイン類似度

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "script_score": {
  7. "query": {
  8. "bool": {
  9. "filter": {
  10. "term": {
  11. "status": "published"
  12. }
  13. }
  14. }
  15. },
  16. "script": {
  17. "source": "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
  18. "params": {
  19. "query_vector": [
  20. 4,
  21. 3.4,
  22. -0.2
  23. ]
  24. }
  25. }
  26. }
  27. },
  28. )
  29. print(resp)
  30. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. bool: {
  8. filter: {
  9. term: {
  10. status: 'published'
  11. }
  12. }
  13. }
  14. },
  15. script: {
  16. source: "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
  17. params: {
  18. query_vector: [
  19. 4,
  20. 3.4,
  21. -0.2
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source:
  16. "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
  17. params: {
  18. query_vector: [4, 3.4, -0.2],
  19. },
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": "cosineSimilarity(params.query_vector, 'my_dense_vector') + 1.0",
  16. "params": {
  17. "query_vector": [4, 3.4, -0.2]
  18. }
  19. }
  20. }
  21. }
  22. }
スクリプトスコア計算が適用されるドキュメントの数を制限するには、フィルターを提供します。
スクリプトはコサイン類似度に1.0を加算して、スコアが負にならないようにします。
スクリプトの最適化を活用するには、スクリプトパラメータとしてクエリベクトルを提供します。

ドキュメントの密なベクトルフィールドの次元数がクエリのベクトルと異なる場合、エラーが発生します。

ドット積

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "script_score": {
  7. "query": {
  8. "bool": {
  9. "filter": {
  10. "term": {
  11. "status": "published"
  12. }
  13. }
  14. }
  15. },
  16. "script": {
  17. "source": "\n double value = dotProduct(params.query_vector, 'my_dense_vector');\n return sigmoid(1, Math.E, -value); \n ",
  18. "params": {
  19. "query_vector": [
  20. 4,
  21. 3.4,
  22. -0.2
  23. ]
  24. }
  25. }
  26. }
  27. },
  28. )
  29. print(resp)
  30. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. bool: {
  8. filter: {
  9. term: {
  10. status: 'published'
  11. }
  12. }
  13. }
  14. },
  15. script: {
  16. source: "\n double value = dotProduct(params.query_vector, 'my_dense_vector');\n return sigmoid(1, Math.E, -value); \n ",
  17. params: {
  18. query_vector: [
  19. 4,
  20. 3.4,
  21. -0.2
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source:
  16. "\n double value = dotProduct(params.query_vector, 'my_dense_vector');\n return sigmoid(1, Math.E, -value); \n ",
  17. params: {
  18. query_vector: [4, 3.4, -0.2],
  19. },
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": """
  16. double value = dotProduct(params.query_vector, 'my_dense_vector');
  17. return sigmoid(1, Math.E, -value);
  18. """,
  19. "params": {
  20. "query_vector": [4, 3.4, -0.2]
  21. }
  22. }
  23. }
  24. }
  25. }
標準のシグモイド関数を使用すると、スコアが負になるのを防ぎます。

L1距離(マンハッタン距離)

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "script_score": {
  7. "query": {
  8. "bool": {
  9. "filter": {
  10. "term": {
  11. "status": "published"
  12. }
  13. }
  14. }
  15. },
  16. "script": {
  17. "source": "1 / (1 + l1norm(params.queryVector, 'my_dense_vector'))",
  18. "params": {
  19. "queryVector": [
  20. 4,
  21. 3.4,
  22. -0.2
  23. ]
  24. }
  25. }
  26. }
  27. },
  28. )
  29. print(resp)
  30. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. bool: {
  8. filter: {
  9. term: {
  10. status: 'published'
  11. }
  12. }
  13. }
  14. },
  15. script: {
  16. source: "1 / (1 + l1norm(params.queryVector, 'my_dense_vector'))",
  17. params: {
  18. "queryVector": [
  19. 4,
  20. 3.4,
  21. -0.2
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source: "1 / (1 + l1norm(params.queryVector, 'my_dense_vector'))",
  16. params: {
  17. queryVector: [4, 3.4, -0.2],
  18. },
  19. },
  20. },
  21. },
  22. });
  23. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": "1 / (1 + l1norm(params.queryVector, 'my_dense_vector'))",
  16. "params": {
  17. "queryVector": [4, 3.4, -0.2]
  18. }
  19. }
  20. }
  21. }
  22. }
cosineSimilarityは類似性を表すのに対し、l1normおよび
l2normは距離または差を表します。これは、ベクトルがより類似しているほど、l1normおよびl2norm関数によって生成されるスコアが低くなることを意味します。
したがって、より類似したベクトルが高いスコアを得る必要があるため、l1normおよびl2normからの出力を反転させました。また、ドキュメントベクトルがクエリと正確に一致する場合に0での除算を避けるために、分母に1を追加しました。

ハミング距離

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "script_score": {
  7. "query": {
  8. "bool": {
  9. "filter": {
  10. "term": {
  11. "status": "published"
  12. }
  13. }
  14. }
  15. },
  16. "script": {
  17. "source": "(24 - hamming(params.queryVector, 'my_byte_dense_vector')) / 24",
  18. "params": {
  19. "queryVector": [
  20. 4,
  21. 3,
  22. 0
  23. ]
  24. }
  25. }
  26. }
  27. },
  28. )
  29. print(resp)
  30. `

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source:
  16. "(24 - hamming(params.queryVector, 'my_byte_dense_vector')) / 24",
  17. params: {
  18. queryVector: [4, 3, 0],
  19. },
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": "(24 - hamming(params.queryVector, 'my_byte_dense_vector')) / 24",
  16. "params": {
  17. "queryVector": [4, 3, 0]
  18. }
  19. }
  20. }
  21. }
  22. }
ハミング距離を計算し、ビットで正規化して0から1のスコアを取得します。

L2距離(ユークリッド距離)

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "script_score": {
  7. "query": {
  8. "bool": {
  9. "filter": {
  10. "term": {
  11. "status": "published"
  12. }
  13. }
  14. }
  15. },
  16. "script": {
  17. "source": "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
  18. "params": {
  19. "queryVector": [
  20. 4,
  21. 3.4,
  22. -0.2
  23. ]
  24. }
  25. }
  26. }
  27. },
  28. )
  29. print(resp)
  30. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. bool: {
  8. filter: {
  9. term: {
  10. status: 'published'
  11. }
  12. }
  13. }
  14. },
  15. script: {
  16. source: "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
  17. params: {
  18. "queryVector": [
  19. 4,
  20. 3.4,
  21. -0.2
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source: "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
  16. params: {
  17. queryVector: [4, 3.4, -0.2],
  18. },
  19. },
  20. },
  21. },
  22. });
  23. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": "1 / (1 + l2norm(params.queryVector, 'my_dense_vector'))",
  16. "params": {
  17. "queryVector": [4, 3.4, -0.2]
  18. }
  19. }
  20. }
  21. }
  22. }

欠落値の確認

ドキュメントにベクトル関数が実行されるベクトルフィールドの値がない場合、エラーが発生します。

フィールドmy_vectorに値があるかどうかをdoc['my_vector'].size() == 0で確認できます。全体のスクリプトは次のようになります:

Js

  1. "source": "doc['my_vector'].size() == 0 ? 0 : cosineSimilarity(params.queryVector, 'my_vector')"

ベクトルへの直接アクセス

次の関数を通じてベクトル値に直接アクセスできます:

  • doc[<field>].vectorValue – ベクトルの値を浮動小数点の配列として返します
  1. - `````doc[<field>].magnitude````` ベクトルの大きさを浮動小数点として返します(バージョン7.5以前に作成されたベクトルの場合、大きさは保存されません。したがって、この関数は呼び出されるたびに新たに計算します)。
  2. `````bit`````ベクトルの場合、これは`````1`````ビットの合計の平方根です。
  3. たとえば、以下のスクリプトはこれらの2つの関数を使用してコサイン類似度を実装します:
  4. #### Python
  5. ``````python
  6. resp = client.search(
  7. index="my-index-000001",
  8. query={
  9. "script_score": {
  10. "query": {
  11. "bool": {
  12. "filter": {
  13. "term": {
  14. "status": "published"
  15. }
  16. }
  17. }
  18. },
  19. "script": {
  20. "source": "\n float[] v = doc['my_dense_vector'].vectorValue;\n float vm = doc['my_dense_vector'].magnitude;\n float dotProduct = 0;\n for (int i = 0; i < v.length; i++) {\n dotProduct += v[i] * params.queryVector[i];\n }\n return dotProduct / (vm * (float) params.queryVectorMag);\n ",
  21. "params": {
  22. "queryVector": [
  23. 4,
  24. 3.4,
  25. -0.2
  26. ],
  27. "queryVectorMag": 5.25357
  28. }
  29. }
  30. }
  31. },
  32. )
  33. print(resp)
  34. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. script_score: {
  6. query: {
  7. bool: {
  8. filter: {
  9. term: {
  10. status: 'published'
  11. }
  12. }
  13. }
  14. },
  15. script: {
  16. source: "\n float[] v = doc['my_dense_vector'].vectorValue;\n float vm = doc['my_dense_vector'].magnitude;\n float dotProduct = 0;\n for (int i = 0; i < v.length; i++) {\n dotProduct += v[i] * params.queryVector[i];\n }\n return dotProduct / (vm * (float) params.queryVectorMag);\n ",
  17. params: {
  18. "queryVector": [
  19. 4,
  20. 3.4,
  21. -0.2
  22. ],
  23. "queryVectorMag": 5.25357
  24. }
  25. }
  26. }
  27. }
  28. }
  29. )
  30. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. script_score: {
  5. query: {
  6. bool: {
  7. filter: {
  8. term: {
  9. status: "published",
  10. },
  11. },
  12. },
  13. },
  14. script: {
  15. source:
  16. "\n float[] v = doc['my_dense_vector'].vectorValue;\n float vm = doc['my_dense_vector'].magnitude;\n float dotProduct = 0;\n for (int i = 0; i < v.length; i++) {\n dotProduct += v[i] * params.queryVector[i];\n }\n return dotProduct / (vm * (float) params.queryVectorMag);\n ",
  17. params: {
  18. queryVector: [4, 3.4, -0.2],
  19. queryVectorMag: 5.25357,
  20. },
  21. },
  22. },
  23. },
  24. });
  25. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "query": {
  4. "script_score": {
  5. "query" : {
  6. "bool" : {
  7. "filter" : {
  8. "term" : {
  9. "status" : "published"
  10. }
  11. }
  12. }
  13. },
  14. "script": {
  15. "source": """
  16. float[] v = doc['my_dense_vector'].vectorValue;
  17. float vm = doc['my_dense_vector'].magnitude;
  18. float dotProduct = 0;
  19. for (int i = 0; i < v.length; i++) {
  20. dotProduct += v[i] * params.queryVector[i];
  21. }
  22. return dotProduct / (vm * (float) params.queryVectorMag);
  23. """,
  24. "params": {
  25. "queryVector": [4, 3.4, -0.2],
  26. "queryVectorMag": 5.25357
  27. }
  28. }
  29. }
  30. }
  31. }

ビットベクトルとベクトル関数

  1. - [`````hamming`````](2ffee97f686b4ace.md#vector-functions-hamming) – ハミング距離を計算します。これは2つのベクトルのビット単位のXORの合計です。
  2. - [`````l1norm`````](2ffee97f686b4ace.md#vector-functions-l1) – L1距離を計算します。これは単に`````hamming`````距離です。
  3. - [`````l2norm`````](2ffee97f686b4ace.md#vector-functions-l2) - L2距離を計算します。これは`````hamming`````距離の平方根です。
  4. 現在、`````cosineSimilarity`````および`````dotProduct`````関数は`````bit`````ベクトルにはサポートされていません。
  5. ### 説明リクエスト
  6. [説明リクエスト](/read/elasticsearch-8-15/d97b1394fff1a56f.md)を使用すると、スコアの各部分がどのように計算されたかの説明が得られます。`````script_score`````クエリは、`````explanation`````パラメータを設定することで独自の説明を追加できます:
  7. #### Python
  8. ``````python
  9. resp = client.explain(
  10. index="my-index-000001",
  11. id="0",
  12. query={
  13. "script_score": {
  14. "query": {
  15. "match": {
  16. "message": "elasticsearch"
  17. }
  18. },
  19. "script": {
  20. "source": "\n long count = doc['count'].value;\n double normalizedCount = count / 10;\n if (explanation != null) {\n explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);\n }\n return normalizedCount;\n "
  21. }
  22. }
  23. },
  24. )
  25. print(resp)
  26. `

Ruby

  1. response = client.explain(
  2. index: 'my-index-000001',
  3. id: 0,
  4. body: {
  5. query: {
  6. script_score: {
  7. query: {
  8. match: {
  9. message: 'elasticsearch'
  10. }
  11. },
  12. script: {
  13. source: "\n long count = doc['count'].value;\n double normalizedCount = count / 10;\n if (explanation != nil) {\n explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);\n }\n return normalizedCount;\n "
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.explain({
  2. index: "my-index-000001",
  3. id: 0,
  4. query: {
  5. script_score: {
  6. query: {
  7. match: {
  8. message: "elasticsearch",
  9. },
  10. },
  11. script: {
  12. source:
  13. "\n long count = doc['count'].value;\n double normalizedCount = count / 10;\n if (explanation != null) {\n explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);\n }\n return normalizedCount;\n ",
  14. },
  15. },
  16. },
  17. });
  18. console.log(response);

コンソール

  1. GET /my-index-000001/_explain/0
  2. {
  3. "query": {
  4. "script_score": {
  5. "query": {
  6. "match": { "message": "elasticsearch" }
  7. },
  8. "script": {
  9. "source": """
  10. long count = doc['count'].value;
  11. double normalizedCount = count / 10;
  12. if (explanation != null) {
  13. explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);
  14. }
  15. return normalizedCount;
  16. """
  17. }
  18. }
  19. }
  20. }

explanationは通常の_searchリクエストで使用する場合はnullになるため、条件付きガードを持つことがベストプラクティスです。