Dense vector field type

dense_vector フィールドタイプは数値の密なベクトルを格納します。密なベクトルフィールドは主に k-nearest neighbor (kNN) 検索 に使用されます。

dense_vector タイプは集約やソートをサポートしていません。

dense_vector フィールドを、element_type に基づいて数値の配列として追加します (デフォルトでは float)。

Python

  1. resp = client.indices.create(
  2. index="my-index",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3
  8. },
  9. "my_text": {
  10. "type": "keyword"
  11. }
  12. }
  13. },
  14. )
  15. print(resp)
  16. resp1 = client.index(
  17. index="my-index",
  18. id="1",
  19. document={
  20. "my_text": "text1",
  21. "my_vector": [
  22. 0.5,
  23. 10,
  24. 6
  25. ]
  26. },
  27. )
  28. print(resp1)
  29. resp2 = client.index(
  30. index="my-index",
  31. id="2",
  32. document={
  33. "my_text": "text2",
  34. "my_vector": [
  35. -0.5,
  36. 10,
  37. 10
  38. ]
  39. },
  40. )
  41. print(resp2)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index',
  3. body: {
  4. mappings: {
  5. properties: {
  6. my_vector: {
  7. type: 'dense_vector',
  8. dims: 3
  9. },
  10. my_text: {
  11. type: 'keyword'
  12. }
  13. }
  14. }
  15. }
  16. )
  17. puts response
  18. response = client.index(
  19. index: 'my-index',
  20. id: 1,
  21. body: {
  22. my_text: 'text1',
  23. my_vector: [
  24. 0.5,
  25. 10,
  26. 6
  27. ]
  28. }
  29. )
  30. puts response
  31. response = client.index(
  32. index: 'my-index',
  33. id: 2,
  34. body: {
  35. my_text: 'text2',
  36. my_vector: [
  37. -0.5,
  38. 10,
  39. 10
  40. ]
  41. }
  42. )
  43. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 3,
  8. },
  9. my_text: {
  10. type: "keyword",
  11. },
  12. },
  13. },
  14. });
  15. console.log(response);
  16. const response1 = await client.index({
  17. index: "my-index",
  18. id: 1,
  19. document: {
  20. my_text: "text1",
  21. my_vector: [0.5, 10, 6],
  22. },
  23. });
  24. console.log(response1);
  25. const response2 = await client.index({
  26. index: "my-index",
  27. id: 2,
  28. document: {
  29. my_text: "text2",
  30. my_vector: [-0.5, 10, 10],
  31. },
  32. });
  33. console.log(response2);

Console

  1. PUT my-index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3
  8. },
  9. "my_text" : {
  10. "type" : "keyword"
  11. }
  12. }
  13. }
  14. }
  15. PUT my-index/_doc/1
  16. {
  17. "my_text" : "text1",
  18. "my_vector" : [0.5, 10, 6]
  19. }
  20. PUT my-index/_doc/2
  21. {
  22. "my_text" : "text2",
  23. "my_vector" : [-0.5, 10, 10]
  24. }

他のほとんどのデータタイプとは異なり、密なベクトルは常に単一値です。1つの dense_vector フィールドに複数の値を格納することはできません。

k-nearest neighbor (kNN) 検索は、クエリベクトルに最も近い k 個のベクトルを、類似度メトリックによって測定します。

密なベクトルフィールドは、script_score クエリ でドキュメントをランク付けするために使用できます。これにより、すべてのドキュメントをスキャンし、類似度によってランク付けすることで、ブルートフォース kNN 検索を実行できます。

多くの場合、ブルートフォース kNN 検索は十分に効率的ではありません。この理由から、dense_vector タイプは、検索 API の knn オプション を通じて迅速な kNN 取得をサポートするために、ベクトルを特化したデータ構造にインデックス化することをサポートしています。

サイズが 128 から 4096 の間の float 要素の未マッピング配列フィールドは、デフォルトの類似度 cosinedense_vector として動的にマッピングされます。フィールドを dense_vector として明示的にマッピングすることで、デフォルトの類似度をオーバーライドできます。

密なベクトルフィールドのインデックス作成はデフォルトで有効になっており、int8_hnsw としてインデックス化されます。インデックス作成が有効な場合、kNN 検索で使用するベクトルの類似度を定義できます:

Python

  1. resp = client.indices.create(
  2. index="my-index-2",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "similarity": "dot_product"
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-2',
  3. body: {
  4. mappings: {
  5. properties: {
  6. my_vector: {
  7. type: 'dense_vector',
  8. dims: 3,
  9. similarity: 'dot_product'
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-2",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 3,
  8. similarity: "dot_product",
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

Console

  1. PUT my-index-2
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "similarity": "dot_product"
  9. }
  10. }
  11. }
  12. }

近似 kNN 検索のためのベクトルのインデックス作成は高コストなプロセスです。index が有効なベクトルフィールドを含むドキュメントを取り込むのにかなりの時間がかかる場合があります。メモリ要件については、k-nearest neighbor (kNN) 検索 を参照してください。

index パラメータを false に設定することで、インデックス作成を無効にできます:

Python

  1. resp = client.indices.create(
  2. index="my-index-2",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": False
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-2',
  3. body: {
  4. mappings: {
  5. properties: {
  6. my_vector: {
  7. type: 'dense_vector',
  8. dims: 3,
  9. index: false
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-2",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 3,
  8. index: false,
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

Console

  1. PUT my-index-2
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": false
  9. }
  10. }
  11. }
  12. }

Elasticsearch は、効率的な kNN 検索をサポートするために HNSW アルゴリズム を使用します。ほとんどの kNN アルゴリズムと同様に、HNSW は結果の精度を犠牲にして速度を向上させる近似手法です。

dense_vector タイプは、float ベクトルを検索する際に必要なメモリフットプリントを削減するために量子化をサポートします。次の 2 つの量子化戦略がサポートされています:

int8 - ベクトルの各次元を 1 バイトの整数に量子化します。これにより、いくつかの精度を犠牲にしてメモリフットプリントを 75% 削減できます。 int4 - ベクトルの各次元を半バイトの整数に量子化します。これにより、いくつかの精度を犠牲にしてメモリフットプリントを 87% 削減できます。

量子化されたインデックスを使用するには、インデックスタイプを int8_hnsw または int4_hnsw に設定できます。float ベクトルをインデックス化する場合、現在のデフォルトインデックスタイプは int8_hnsw です。

量子化は、データのライフサイクル全体にわたって再ランク付け、再インデックス作成、および量子化の改善のために、ディスク上に生の float ベクトル値を保持し続けます。これは、量子化されたベクトルと生のベクトルを保存するオーバーヘッドのために、int8 で ~25%、int4 で ~12.5% のディスク使用量が増加することを意味します。

int4 量子化は、ベクトル次元の偶数を必要とします。

バイト量子化インデックスを作成する方法の例を次に示します:

Python

  1. resp = client.indices.create(
  2. index="my-byte-quantized-index",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": True,
  9. "index_options": {
  10. "type": "int8_hnsw"
  11. }
  12. }
  13. }
  14. },
  15. )
  16. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-byte-quantized-index',
  3. body: {
  4. mappings: {
  5. properties: {
  6. my_vector: {
  7. type: 'dense_vector',
  8. dims: 3,
  9. index: true,
  10. index_options: {
  11. type: 'int8_hnsw'
  12. }
  13. }
  14. }
  15. }
  16. }
  17. )
  18. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-byte-quantized-index",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 3,
  8. index: true,
  9. index_options: {
  10. type: "int8_hnsw",
  11. },
  12. },
  13. },
  14. },
  15. });
  16. console.log(response);

Console

  1. PUT my-byte-quantized-index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": true,
  9. "index_options": {
  10. "type": "int8_hnsw"
  11. }
  12. }
  13. }
  14. }
  15. }

半バイト量子化インデックスを作成する方法の例を次に示します:

Python

  1. resp = client.indices.create(
  2. index="my-byte-quantized-index",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 4,
  8. "index": True,
  9. "index_options": {
  10. "type": "int4_hnsw"
  11. }
  12. }
  13. }
  14. },
  15. )
  16. print(resp)

Js

  1. const response = await client.indices.create({
  2. index: "my-byte-quantized-index",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 4,
  8. index: true,
  9. index_options: {
  10. type: "int4_hnsw",
  11. },
  12. },
  13. },
  14. },
  15. });
  16. console.log(response);

Console

  1. PUT my-byte-quantized-index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 4,
  8. "index": true,
  9. "index_options": {
  10. "type": "int4_hnsw"
  11. }
  12. }
  13. }
  14. }
  15. }

Parameters for dense vector fields

次のマッピングパラメータが受け入れられます:

  • element_type
  • (オプション、文字列) ベクトルをエンコードするために使用されるデータタイプ。サポートされているデータタイプは float (デフォルト)、byte、およびビットです。

element_type の有効な値

  • float
  • 各次元ごとに 4 バイトの浮動小数点値をインデックス化します。これがデフォルト値です。
  • byte
  • 各次元ごとに 1 バイトの整数値をインデックス化します。
  • bit
  • 各次元ごとに 1 ビットをインデックス化します。非常に高次元のベクトルや、特にビットベクトルをサポートするモデルに便利です。注意:bit を使用する場合、次元数は 8 の倍数でなければならず、ビット数を表す必要があります。

  • dims

  • (オプション、整数) ベクトル次元の数。4096 を超えることはできません。dims が指定されていない場合、フィールドに追加された最初のベクトルの長さに設定されます。
  • index
  • (オプション、ブール値) true の場合、このフィールドを kNN 検索 API を使用して検索できます。デフォルトは true です。

  • similarity
  • (オプション*、文字列) kNN 検索で使用するベクトルの類似度メトリック。ドキュメントは、クエリベクトルに対するベクトルフィールドの類似度によってランク付けされます。各ドキュメントの _score は、スコアが正であり、より大きなスコアがより高いランクに対応するように、類似度から導出されます。element_type: bit が指定されていない場合、l2_norm にデフォルト設定されます。

bit ベクトルは、l2_norm を類似度メトリックとしてのみサポートします。

  • このパラメータは、indextrue の場合にのみ指定できます。
  • .similarity の有効な値

詳細

  • l2_norm
  • ベクトル間の L2 距離(ユークリッド距離とも呼ばれる)に基づいて類似度を計算します。ドキュメント _score1 / (1 + l2_norm(query, vector)^2) として計算されます。

bit ベクトルの場合、l2_norm を使用する代わりに、ベクトル間の hamming 距離が使用されます。_score 変換は (numBits - hamming(a, b)) / numBits です。

  • dot_product
  • 2 つの単位ベクトルの内積を計算します。このオプションは、コサイン類似度を計算するための最適化された方法を提供します。制約と計算されたスコアは element_type によって定義されます。
    element_typefloat の場合、すべてのベクトルは単位長でなければならず、ドキュメントベクトルとクエリベクトルの両方を含みます。ドキュメント _score(1 + dot_product(query, vector)) / 2 として計算されます。
    element_typebyte の場合、すべてのベクトルは同じ長さでなければならず、ドキュメントベクトルとクエリベクトルの両方を含むか、結果が不正確になります。ドキュメント _score0.5 + (dot_product(query, vector) / (32768 * dims)) として計算され、dims はベクトルごとの次元数です。
  • cosine
  • コサイン類似度を計算します。インデックス作成中、Elasticsearch は自動的に cosine 類似度を持つベクトルを単位長に正規化します。これにより、類似度を計算するために内部的に dot_product を使用できるようになり、より効率的になります。元の未正規化ベクトルには、スクリプトを通じて引き続きアクセスできます。ドキュメント _score(1 + cosine(query, vector)) / 2 として計算されます。cosine 類似度は、ゼロの大きさのベクトルを許可しません。コサインはこの場合に定義されていないためです。
  • max_inner_product
  • 2 つのベクトルの最大内積を計算します。これは dot_product に似ていますが、ベクトルを正規化する必要はありません。これは、各ベクトルの大きさがスコアに大きく影響する可能性があることを意味します。ドキュメント _score は負の値を防ぐために調整されます。max_inner_product< 0 の場合、_score1 / (1 + -1 * max_inner_product(query, vector)) です。非負の max_inner_product 結果の場合、_scoremax_inner_product(query, vector) + 1 として計算されます。

similarity パラメータは、概念的には関連していますが、text フィールド similarity とは異なり、異なるオプションセットを受け入れます。

  • index_options
  • (オプション*、オブジェクト) kNN インデックス作成アルゴリズムを構成するオプションセクション。HNSW アルゴリズムには、データ構造の構築に影響を与える 2 つの内部パラメータがあります。これらは、インデックス作成速度が遅くなる代わりに、結果の精度を向上させるために調整できます。
  • このパラメータは、indextrue の場合にのみ指定できます。
    index_options のプロパティ
    • type
    • (必須、文字列) 使用する kNN アルゴリズムのタイプ。次のいずれかである必要があります:
      • hnsw - これは、スケーラブルな近似 kNN 検索のために HNSW アルゴリズム を利用します。これはすべての element_type 値をサポートします。
      • int8_hnsw - 浮動小数点ベクトルのデフォルトインデックスタイプです。これは、element_typefloat に対してスケーラブルな近似 kNN 検索のために HNSW アルゴリズム を自動的にスカラー量子化と共に利用します。これにより、いくつかの精度を犠牲にしてメモリフットプリントを 4 倍削減できます。 kNN 検索のための自動量子化ベクトル を参照してください。
      • int4_hnsw - これは、element_typefloat に対してスケーラブルな近似 kNN 検索のために HNSW アルゴリズム を自動的にスカラー量子化と共に利用します。これにより、いくつかの精度を犠牲にしてメモリフットプリントを 8 倍削減できます。 kNN 検索のための自動量子化ベクトル を参照してください。
      • flat - これは、正確な kNN 検索のためにブルートフォース検索アルゴリズムを利用します。これはすべての element_type 値をサポートします。
      • int8_flat - これは、自動的にスカラー量子化を行うブルートフォース検索アルゴリズムを利用します。element_typefloat のみをサポートします。
      • int4_flat - これは、自動的に半バイトスカラー量子化を行うブルートフォース検索アルゴリズムを利用します。element_typefloat のみをサポートします。
    • m
    • (オプション、整数) HNSW グラフ内の各ノードが接続される隣接ノードの数。デフォルトは 16 です。hnswint8_hnsw、および int4_hnsw インデックスタイプにのみ適用されます。
    • ef_construction
    • (オプション、整数) 各新しいノードの最近傍リストを構成する際に追跡する候補の数。デフォルトは 100 です。hnswint8_hnsw、および int4_hnsw インデックスタイプにのみ適用されます。
    • confidence_interval
    • (オプション、浮動小数点) int8_hnswint4_hnswint8_flat、および int4_flat インデックスタイプにのみ適用されます。ベクトルを量子化する際に使用する信頼区間。0.901.0 の間の任意の値、または正確に 0 である必要があります。値が 0 の場合、これは最適化された量子化のために動的量子化を計算することを示します。0.901.0 の間の場合、この値は量子化しきい値を計算する際に使用される値を制限します。たとえば、0.95 の値は、量子化しきい値を計算する際に値の中間 95% のみを使用します(最高および最低の 2.5% の値は無視されます)。1/(dims + 1)int8 量子化ベクトルに、0int4 の動的量子化計算にデフォルト設定されます。

Synthetic _source

合成 _source は、TSDB インデックス (index.modetime_series に設定されているインデックス) のみで一般に利用可能です。他のインデックスでは、合成 _source は技術プレビュー中です。技術プレビューの機能は、将来のリリースで変更または削除される可能性があります。Elastic は問題を修正するために取り組みますが、技術プレビューの機能は公式 GA 機能のサポート SLA の対象ではありません。

dense_vector フィールドは 合成 _source をサポートします。

Indexing & Searching bit vectors

element_type: bit を使用すると、すべてのベクトルがビットベクトルとして扱われます。ビットベクトルは、各次元ごとに単一のビットのみを利用し、内部的にはバイトとしてエンコードされます。これは、非常に高次元のベクトルやモデルに便利です。

bit を使用する場合、次元数は 8 の倍数でなければならず、ビット数を表す必要があります。さらに、bit ベクトルでは、典型的なベクトル類似度値は実質的にすべて同じスコアになります。たとえば、hamming 距離を使用します。

2 つの byte[] 配列を比較してみましょう。それぞれが 40 個の個別のビットを表します。

[-127, 0, 1, 42, 127] ビット 1000000100000000000000010010101001111111 [127, -127, 0, 1, 42] ビット 0111111110000001000000000000000100101010

これら 2 つのビットベクトルを比較する際、最初に hamming 距離 を取ります。

xor 結果:

  1. 1000000100000000000000010010101001111111
  2. ^
  3. 0111111110000001000000000000000100101010
  4. =
  5. 1111111010000001000000010010101101010101

次に、xor 結果の 1 ビットのカウントを集めます: 18。スコアリングのためにスケールするために、ビットの総数から引き、ビットの総数で割ります: (40 - 18) / 40 = 0.55。これが、これら 2 つのベクトル間の _score になります。

ビットベクトルのインデックス作成と検索の例を次に示します:

Python

  1. resp = client.indices.create(
  2. index="my-bit-vectors",
  3. mappings={
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 40,
  8. "element_type": "bit"
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Js

  1. const response = await client.indices.create({
  2. index: "my-bit-vectors",
  3. mappings: {
  4. properties: {
  5. my_vector: {
  6. type: "dense_vector",
  7. dims: 40,
  8. element_type: "bit",
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

Console

  1. PUT my-bit-vectors
  2. {
  3. "mappings": {
  4. "properties": {
  5. "my_vector": {
  6. "type": "dense_vector",
  7. "dims": 40,
  8. "element_type": "bit"
  9. }
  10. }
  11. }
  12. }
ビット数を表す次元数

Python

  1. resp = client.bulk(
  2. index="my-bit-vectors",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {
  7. "_id": "1"
  8. }
  9. },
  10. {
  11. "my_vector": [
  12. 127,
  13. -127,
  14. 0,
  15. 1,
  16. 42
  17. ]
  18. },
  19. {
  20. "index": {
  21. "_id": "2"
  22. }
  23. },
  24. {
  25. "my_vector": "8100012a7f"
  26. }
  27. ],
  28. )
  29. print(resp)

Js

  1. const response = await client.bulk({
  2. index: "my-bit-vectors",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {
  7. _id: "1",
  8. },
  9. },
  10. {
  11. my_vector: [127, -127, 0, 1, 42],
  12. },
  13. {
  14. index: {
  15. _id: "2",
  16. },
  17. },
  18. {
  19. my_vector: "8100012a7f",
  20. },
  21. ],
  22. });
  23. console.log(response);

Console

  1. POST /my-bit-vectors/_bulk?refresh
  2. {"index": {"_id" : "1"}}
  3. {"my_vector": [127, -127, 0, 1, 42]}
  4. {"index": {"_id" : "2"}}
  5. {"my_vector": "8100012a7f"}
40 ビット次元ベクトルを表す 5 バイト
40 ビット次元ベクトルを表す 16 進数文字列

次に、検索時に knn クエリを使用して、類似のビットベクトルを検索できます:

Python

  1. resp = client.search(
  2. index="my-bit-vectors",
  3. filter_path="hits.hits",
  4. query={
  5. "knn": {
  6. "query_vector": [
  7. 127,
  8. -127,
  9. 0,
  10. 1,
  11. 42
  12. ],
  13. "field": "my_vector"
  14. }
  15. },
  16. )
  17. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-bit-vectors",
  3. filter_path: "hits.hits",
  4. query: {
  5. knn: {
  6. query_vector: [127, -127, 0, 1, 42],
  7. field: "my_vector",
  8. },
  9. },
  10. });
  11. console.log(response);

Console

  1. POST /my-bit-vectors/_search?filter_path=hits.hits
  2. {
  3. "query": {
  4. "knn": {
  5. "query_vector": [127, -127, 0, 1, 42],
  6. "field": "my_vector"
  7. }
  8. }
  9. }

Console-Result

  1. {
  2. "hits": {
  3. "hits": [
  4. {
  5. "_index": "my-bit-vectors",
  6. "_id": "1",
  7. "_score": 1.0,
  8. "_source": {
  9. "my_vector": [
  10. 127,
  11. -127,
  12. 0,
  13. 1,
  14. 42
  15. ]
  16. }
  17. },
  18. {
  19. "_index": "my-bit-vectors",
  20. "_id": "2",
  21. "_score": 0.55,
  22. "_source": {
  23. "my_vector": "8100012a7f"
  24. }
  25. }
  26. ]
  27. }
  28. }