Knn query

k 最近のベクトルをクエリベクトルに対して、類似度メトリックによって測定します。knn クエリは、インデックスされた dense_vectors に対して近似検索を通じて最近のベクトルを見つけます。近似 kNN 検索を行うための推奨方法は、検索リクエストの トップレベル knn セクション を通じて行うことです。knn クエリは、他のクエリと組み合わせる必要がある専門的なケースに予約されています。

Example request

Python

  1. resp = client.indices.create(
  2. index="my-image-index",
  3. mappings={
  4. "properties": {
  5. "image-vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": True,
  9. "similarity": "l2_norm"
  10. },
  11. "file-type": {
  12. "type": "keyword"
  13. },
  14. "title": {
  15. "type": "text"
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-image-index',
  3. body: {
  4. mappings: {
  5. properties: {
  6. "image-vector": {
  7. type: 'dense_vector',
  8. dims: 3,
  9. index: true,
  10. similarity: 'l2_norm'
  11. },
  12. "file-type": {
  13. type: 'keyword'
  14. },
  15. title: {
  16. type: 'text'
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-image-index",
  3. mappings: {
  4. properties: {
  5. "image-vector": {
  6. type: "dense_vector",
  7. dims: 3,
  8. index: true,
  9. similarity: "l2_norm",
  10. },
  11. "file-type": {
  12. type: "keyword",
  13. },
  14. title: {
  15. type: "text",
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

Console

  1. PUT my-image-index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "image-vector": {
  6. "type": "dense_vector",
  7. "dims": 3,
  8. "index": true,
  9. "similarity": "l2_norm"
  10. },
  11. "file-type": {
  12. "type": "keyword"
  13. },
  14. "title": {
  15. "type": "text"
  16. }
  17. }
  18. }
  19. }
  • 1. データをインデックスします。

Python

  1. resp = client.bulk(
  2. index="my-image-index",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {
  7. "_id": "1"
  8. }
  9. },
  10. {
  11. "image-vector": [
  12. 1,
  13. 5,
  14. -20
  15. ],
  16. "file-type": "jpg",
  17. "title": "mountain lake"
  18. },
  19. {
  20. "index": {
  21. "_id": "2"
  22. }
  23. },
  24. {
  25. "image-vector": [
  26. 42,
  27. 8,
  28. -15
  29. ],
  30. "file-type": "png",
  31. "title": "frozen lake"
  32. },
  33. {
  34. "index": {
  35. "_id": "3"
  36. }
  37. },
  38. {
  39. "image-vector": [
  40. 15,
  41. 11,
  42. 23
  43. ],
  44. "file-type": "jpg",
  45. "title": "mountain lake lodge"
  46. }
  47. ],
  48. )
  49. print(resp)

Ruby

  1. response = client.bulk(
  2. index: 'my-image-index',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {
  7. _id: '1'
  8. }
  9. },
  10. {
  11. "image-vector": [
  12. 1,
  13. 5,
  14. -20
  15. ],
  16. "file-type": 'jpg',
  17. title: 'mountain lake'
  18. },
  19. {
  20. index: {
  21. _id: '2'
  22. }
  23. },
  24. {
  25. "image-vector": [
  26. 42,
  27. 8,
  28. -15
  29. ],
  30. "file-type": 'png',
  31. title: 'frozen lake'
  32. },
  33. {
  34. index: {
  35. _id: '3'
  36. }
  37. },
  38. {
  39. "image-vector": [
  40. 15,
  41. 11,
  42. 23
  43. ],
  44. "file-type": 'jpg',
  45. title: 'mountain lake lodge'
  46. }
  47. ]
  48. )
  49. puts response

Js

  1. const response = await client.bulk({
  2. index: "my-image-index",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {
  7. _id: "1",
  8. },
  9. },
  10. {
  11. "image-vector": [1, 5, -20],
  12. "file-type": "jpg",
  13. title: "mountain lake",
  14. },
  15. {
  16. index: {
  17. _id: "2",
  18. },
  19. },
  20. {
  21. "image-vector": [42, 8, -15],
  22. "file-type": "png",
  23. title: "frozen lake",
  24. },
  25. {
  26. index: {
  27. _id: "3",
  28. },
  29. },
  30. {
  31. "image-vector": [15, 11, 23],
  32. "file-type": "jpg",
  33. title: "mountain lake lodge",
  34. },
  35. ],
  36. });
  37. console.log(response);

Console

  1. POST my-image-index/_bulk?refresh=true
  2. { "index": { "_id": "1" } }
  3. { "image-vector": [1, 5, -20], "file-type": "jpg", "title": "mountain lake" }
  4. { "index": { "_id": "2" } }
  5. { "image-vector": [42, 8, -15], "file-type": "png", "title": "frozen lake"}
  6. { "index": { "_id": "3" } }
  7. { "image-vector": [15, 11, 23], "file-type": "jpg", "title": "mountain lake lodge" }
  • 2. knn クエリを使用して検索を実行し、各シャードから最も近い 10 のベクトルを要求し、シャードの結果を組み合わせて上位 3 のグローバル結果を取得します。

Python

  1. resp = client.search(
  2. index="my-image-index",
  3. size=3,
  4. query={
  5. "knn": {
  6. "field": "image-vector",
  7. "query_vector": [
  8. -5,
  9. 9,
  10. -12
  11. ],
  12. "k": 10
  13. }
  14. },
  15. )
  16. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-image-index",
  3. size: 3,
  4. query: {
  5. knn: {
  6. field: "image-vector",
  7. query_vector: [-5, 9, -12],
  8. k: 10,
  9. },
  10. },
  11. });
  12. console.log(response);

Console

  1. POST my-image-index/_search
  2. {
  3. "size" : 3,
  4. "query" : {
  5. "knn": {
  6. "field": "image-vector",
  7. "query_vector": [-5, 9, -12],
  8. "k": 10
  9. }
  10. }
  11. }

Top-level parameters for knn

  • field
  • (必須、文字列) 検索対象のベクトルフィールドの名前。インデックスが有効な dense_vector フィールドである必要があります。
  • query_vector
  • (オプション、浮動小数点数または文字列の配列) クエリベクトル。検索対象のベクトルフィールドと同じ次元数を持つ必要があります。浮動小数点数の配列または16進エンコードされたバイトベクトルのいずれかでなければなりません。これか query_vector_builder のいずれかを提供する必要があります。
  • query_vector_builder
  • (オプション、オブジェクト) クエリベクトルビルダー。リクエストを実行する前にクエリベクトルを構築する方法を示す構成オブジェクト。query_vector_builder または query_vector のいずれかを提供する必要がありますが、両方は提供できません。詳細については、意味的検索を実行するを参照してください。
  • k
  • (オプション、整数) 各シャードから返す最近の隣人の数。Elasticsearch は各シャードから k 結果を収集し、それをマージしてグローバルなトップ結果を見つけます。この値は num_candidates 以下でなければなりません。デフォルトは num_candidates です。
  • num_candidates
  • (オプション、整数) knn 検索を行う際に各シャードで考慮する最近の隣人候補の数。10,000 を超えることはできません。num_candidates を増やすと、最終結果の精度が向上する傾向があります。k が設定されている場合は 1.5 * k がデフォルト、k が設定されていない場合は 1.5 * size がデフォルトです。
  • filter
  • (オプション、クエリオブジェクト) 一致する可能性のあるドキュメントをフィルタリングするためのクエリ。kNN 検索は、このフィルタにも一致するトップドキュメントを返します。値は単一のクエリまたはクエリのリストであることができます。filter が提供されていない場合、すべてのドキュメントが一致することが許可されます。
    フィルタはプレフィルタであり、num_candidates に一致するドキュメントが返されることを保証するために、近似 kNN 検索 中に 適用されます。
  • similarity
  • (オプション、浮動小数点) ドキュメントが一致と見なされるために必要な最小類似度。計算された類似度値は、使用される生の similarity に関連しています。ドキュメントスコアではありません。一致したドキュメントは、similarity に従ってスコア付けされ、提供された boost が適用されます。
  • boost
  • (オプション、浮動小数点) 一致したドキュメントのスコアを乗算するために使用される浮動小数点数。この値は負であってはなりません。デフォルトは 1.0 です。
  • _name
  • (オプション、文字列) クエリを識別するための名前フィールド

Pre-filters and post-filters in knn query

kNN クエリに一致するドキュメントをフィルタリングする方法は 2 つあります:

  • 1. プレフィルタリング – フィルタは近似 kNN 検索中に適用され、k に一致するドキュメントが返されることを保証します。
  • 2. ポストフィルタリング – フィルタは近似 kNN 検索が完了した後に適用され、十分な一致するドキュメントがあっても k より少ない結果が得られます。

プレフィルタリングは、filter パラメータを通じて knn クエリでサポートされています。また、エイリアスからのフィルタもプレフィルタとして適用されます。

Query DSL ツリー内の他のすべてのフィルタはポストフィルタとして適用されます。たとえば、knn クエリは、最も近いベクトルを持つ上位 3 ドキュメント (k=3) を見つけ、それをポストフィルタである term フィルタと組み合わせます。最終的なドキュメントセットには、ポストフィルタを通過した単一のドキュメントのみが含まれます。

Python

  1. resp = client.search(
  2. index="my-image-index",
  3. size=10,
  4. query={
  5. "bool": {
  6. "must": {
  7. "knn": {
  8. "field": "image-vector",
  9. "query_vector": [
  10. -5,
  11. 9,
  12. -12
  13. ],
  14. "k": 3
  15. }
  16. },
  17. "filter": {
  18. "term": {
  19. "file-type": "png"
  20. }
  21. }
  22. }
  23. },
  24. )
  25. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-image-index",
  3. size: 10,
  4. query: {
  5. bool: {
  6. must: {
  7. knn: {
  8. field: "image-vector",
  9. query_vector: [-5, 9, -12],
  10. k: 3,
  11. },
  12. },
  13. filter: {
  14. term: {
  15. "file-type": "png",
  16. },
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

Console

  1. POST my-image-index/_search
  2. {
  3. "size" : 10,
  4. "query" : {
  5. "bool" : {
  6. "must" : {
  7. "knn": {
  8. "field": "image-vector",
  9. "query_vector": [-5, 9, -12],
  10. "k": 3
  11. }
  12. },
  13. "filter" : {
  14. "term" : { "file-type" : "png" }
  15. }
  16. }
  17. }
  18. }

Hybrid search with knn query

Knn クエリは、kNN クエリが他のレキシカルクエリと組み合わされるハイブリッド検索の一部として使用できます。たとえば、以下のクエリは、title に一致する mountain lake を持つドキュメントを見つけ、query_vector に最も近い画像ベクトルを持つ上位 10 ドキュメントと組み合わせます。組み合わされたドキュメントはスコア付けされ、上位 3 のスコアが最も高いドキュメントが返されます。

+

Python

  1. resp = client.search(
  2. index="my-image-index",
  3. size=3,
  4. query={
  5. "bool": {
  6. "should": [
  7. {
  8. "match": {
  9. "title": {
  10. "query": "mountain lake",
  11. "boost": 1
  12. }
  13. }
  14. },
  15. {
  16. "knn": {
  17. "field": "image-vector",
  18. "query_vector": [
  19. -5,
  20. 9,
  21. -12
  22. ],
  23. "k": 10,
  24. "boost": 2
  25. }
  26. }
  27. ]
  28. }
  29. },
  30. )
  31. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-image-index",
  3. size: 3,
  4. query: {
  5. bool: {
  6. should: [
  7. {
  8. match: {
  9. title: {
  10. query: "mountain lake",
  11. boost: 1,
  12. },
  13. },
  14. },
  15. {
  16. knn: {
  17. field: "image-vector",
  18. query_vector: [-5, 9, -12],
  19. k: 10,
  20. boost: 2,
  21. },
  22. },
  23. ],
  24. },
  25. },
  26. });
  27. console.log(response);

Console

  1. POST my-image-index/_search
  2. {
  3. "size" : 3,
  4. "query": {
  5. "bool": {
  6. "should": [
  7. {
  8. "match": {
  9. "title": {
  10. "query": "mountain lake",
  11. "boost": 1
  12. }
  13. }
  14. },
  15. {
  16. "knn": {
  17. "field": "image-vector",
  18. "query_vector": [-5, 9, -12],
  19. "k": 10,
  20. "boost": 2
  21. }
  22. }
  23. ]
  24. }
  25. }
  26. }

Knn query inside a nested query

knn クエリは、ネストされたクエリ内で使用できます。ここでの動作は、トップレベルのネストされた kNN 検索 に似ています:

  • ネストされた dense_vectors に対する kNN 検索は、トップレベルのドキュメントに対してトップ結果を多様化します
  • トップレベルのドキュメントメタデータに対する filter がサポートされており、プレフィルタとして機能します
  • filternested フィールドメタデータに対してサポートされていません

サンプルクエリは以下のようになります:

Js

  1. {
  2. "query" : {
  3. "nested" : {
  4. "path" : "paragraph",
  5. "query" : {
  6. "knn": {
  7. "query_vector": [
  8. 0.45,
  9. 45
  10. ],
  11. "field": "paragraph.vector",
  12. "num_candidates": 2
  13. }
  14. }
  15. }
  16. }
  17. }

Knn query with aggregations

knn クエリは、各シャードからのトップ k ドキュメントに対して集計を計算します。したがって、集計からの最終結果には k * number_of_shards ドキュメントが含まれます。これは、トップレベルの knn セクション とは異なり、集計はグローバルなトップ k 最近のドキュメントに対して計算されます。