Knn query
k 最近のベクトルをクエリベクトルに対して、類似度メトリックによって測定します。knn クエリは、インデックスされた dense_vectors に対して近似検索を通じて最近のベクトルを見つけます。近似 kNN 検索を行うための推奨方法は、検索リクエストの トップレベル knn セクション を通じて行うことです。knn クエリは、他のクエリと組み合わせる必要がある専門的なケースに予約されています。
Example request
Python
resp = client.indices.create(
index="my-image-index",
mappings={
"properties": {
"image-vector": {
"type": "dense_vector",
"dims": 3,
"index": True,
"similarity": "l2_norm"
},
"file-type": {
"type": "keyword"
},
"title": {
"type": "text"
}
}
},
)
print(resp)
Ruby
response = client.indices.create(
index: 'my-image-index',
body: {
mappings: {
properties: {
"image-vector": {
type: 'dense_vector',
dims: 3,
index: true,
similarity: 'l2_norm'
},
"file-type": {
type: 'keyword'
},
title: {
type: 'text'
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "my-image-index",
mappings: {
properties: {
"image-vector": {
type: "dense_vector",
dims: 3,
index: true,
similarity: "l2_norm",
},
"file-type": {
type: "keyword",
},
title: {
type: "text",
},
},
},
});
console.log(response);
Console
PUT my-image-index
{
"mappings": {
"properties": {
"image-vector": {
"type": "dense_vector",
"dims": 3,
"index": true,
"similarity": "l2_norm"
},
"file-type": {
"type": "keyword"
},
"title": {
"type": "text"
}
}
}
}
- 1. データをインデックスします。
Python
resp = client.bulk(
index="my-image-index",
refresh=True,
operations=[
{
"index": {
"_id": "1"
}
},
{
"image-vector": [
1,
5,
-20
],
"file-type": "jpg",
"title": "mountain lake"
},
{
"index": {
"_id": "2"
}
},
{
"image-vector": [
42,
8,
-15
],
"file-type": "png",
"title": "frozen lake"
},
{
"index": {
"_id": "3"
}
},
{
"image-vector": [
15,
11,
23
],
"file-type": "jpg",
"title": "mountain lake lodge"
}
],
)
print(resp)
Ruby
response = client.bulk(
index: 'my-image-index',
refresh: true,
body: [
{
index: {
_id: '1'
}
},
{
"image-vector": [
1,
5,
-20
],
"file-type": 'jpg',
title: 'mountain lake'
},
{
index: {
_id: '2'
}
},
{
"image-vector": [
42,
8,
-15
],
"file-type": 'png',
title: 'frozen lake'
},
{
index: {
_id: '3'
}
},
{
"image-vector": [
15,
11,
23
],
"file-type": 'jpg',
title: 'mountain lake lodge'
}
]
)
puts response
Js
const response = await client.bulk({
index: "my-image-index",
refresh: "true",
operations: [
{
index: {
_id: "1",
},
},
{
"image-vector": [1, 5, -20],
"file-type": "jpg",
title: "mountain lake",
},
{
index: {
_id: "2",
},
},
{
"image-vector": [42, 8, -15],
"file-type": "png",
title: "frozen lake",
},
{
index: {
_id: "3",
},
},
{
"image-vector": [15, 11, 23],
"file-type": "jpg",
title: "mountain lake lodge",
},
],
});
console.log(response);
Console
POST my-image-index/_bulk?refresh=true
{ "index": { "_id": "1" } }
{ "image-vector": [1, 5, -20], "file-type": "jpg", "title": "mountain lake" }
{ "index": { "_id": "2" } }
{ "image-vector": [42, 8, -15], "file-type": "png", "title": "frozen lake"}
{ "index": { "_id": "3" } }
{ "image-vector": [15, 11, 23], "file-type": "jpg", "title": "mountain lake lodge" }
- 2.
knn
クエリを使用して検索を実行し、各シャードから最も近い 10 のベクトルを要求し、シャードの結果を組み合わせて上位 3 のグローバル結果を取得します。
Python
resp = client.search(
index="my-image-index",
size=3,
query={
"knn": {
"field": "image-vector",
"query_vector": [
-5,
9,
-12
],
"k": 10
}
},
)
print(resp)
Js
const response = await client.search({
index: "my-image-index",
size: 3,
query: {
knn: {
field: "image-vector",
query_vector: [-5, 9, -12],
k: 10,
},
},
});
console.log(response);
Console
POST my-image-index/_search
{
"size" : 3,
"query" : {
"knn": {
"field": "image-vector",
"query_vector": [-5, 9, -12],
"k": 10
}
}
}
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
resp = client.search(
index="my-image-index",
size=10,
query={
"bool": {
"must": {
"knn": {
"field": "image-vector",
"query_vector": [
-5,
9,
-12
],
"k": 3
}
},
"filter": {
"term": {
"file-type": "png"
}
}
}
},
)
print(resp)
Js
const response = await client.search({
index: "my-image-index",
size: 10,
query: {
bool: {
must: {
knn: {
field: "image-vector",
query_vector: [-5, 9, -12],
k: 3,
},
},
filter: {
term: {
"file-type": "png",
},
},
},
},
});
console.log(response);
Console
POST my-image-index/_search
{
"size" : 10,
"query" : {
"bool" : {
"must" : {
"knn": {
"field": "image-vector",
"query_vector": [-5, 9, -12],
"k": 3
}
},
"filter" : {
"term" : { "file-type" : "png" }
}
}
}
}
Hybrid search with knn query
Knn クエリは、kNN クエリが他のレキシカルクエリと組み合わされるハイブリッド検索の一部として使用できます。たとえば、以下のクエリは、title
に一致する mountain lake
を持つドキュメントを見つけ、query_vector
に最も近い画像ベクトルを持つ上位 10 ドキュメントと組み合わせます。組み合わされたドキュメントはスコア付けされ、上位 3 のスコアが最も高いドキュメントが返されます。
+
Python
resp = client.search(
index="my-image-index",
size=3,
query={
"bool": {
"should": [
{
"match": {
"title": {
"query": "mountain lake",
"boost": 1
}
}
},
{
"knn": {
"field": "image-vector",
"query_vector": [
-5,
9,
-12
],
"k": 10,
"boost": 2
}
}
]
}
},
)
print(resp)
Js
const response = await client.search({
index: "my-image-index",
size: 3,
query: {
bool: {
should: [
{
match: {
title: {
query: "mountain lake",
boost: 1,
},
},
},
{
knn: {
field: "image-vector",
query_vector: [-5, 9, -12],
k: 10,
boost: 2,
},
},
],
},
},
});
console.log(response);
Console
POST my-image-index/_search
{
"size" : 3,
"query": {
"bool": {
"should": [
{
"match": {
"title": {
"query": "mountain lake",
"boost": 1
}
}
},
{
"knn": {
"field": "image-vector",
"query_vector": [-5, 9, -12],
"k": 10,
"boost": 2
}
}
]
}
}
}
Knn query inside a nested query
knn
クエリは、ネストされたクエリ内で使用できます。ここでの動作は、トップレベルのネストされた kNN 検索 に似ています:
- ネストされた dense_vectors に対する kNN 検索は、トップレベルのドキュメントに対してトップ結果を多様化します
- トップレベルのドキュメントメタデータに対する
filter
がサポートされており、プレフィルタとして機能します filter
はnested
フィールドメタデータに対してサポートされていません
サンプルクエリは以下のようになります:
Js
{
"query" : {
"nested" : {
"path" : "paragraph",
"query" : {
"knn": {
"query_vector": [
0.45,
45
],
"field": "paragraph.vector",
"num_candidates": 2
}
}
}
}
}
Knn query with aggregations
knn
クエリは、各シャードからのトップ k
ドキュメントに対して集計を計算します。したがって、集計からの最終結果には k * number_of_shards
ドキュメントが含まれます。これは、トップレベルの knn セクション とは異なり、集計はグローバルなトップ k
最近のドキュメントに対して計算されます。