テナントごと、またはナレッジベースごとに個別のインデックスを維持することなく、データを分離して検索できます。この例では、1 つのコレクション (統一されたフィールド定義を持つデータセット) を使用して 2 つのテナントを管理します。テナントは 2 つのスライス (ビジネスデータパーティション) である tenant-a と tenant-b にマッピングされ、データの書き込みおよびクエリ時に _slice を通じてテナントを指定します。この例では、スライス名がテナント ID となります。また、ナレッジベースなど、他のビジネス識別子にちなんでスライスに名前を付けることもできます。ビジネス識別子でデータスコープを選択することを、デフォルトモードである namespace モード (exact) と呼びます。ステップ 3 では、他のクエリスコープを使用する場合について説明します。
アプリケーションは、コレクション名とビジネススライス名を通じてデータにアクセスします。 スライスはデータスコープを制限するものであり、アカウントの権限境界ではありません。 アプリケーションは、引き続きテナントの ID を検証し、アクセスを認可する必要があります。
最初の検索を完了するには、コレクションの作成 → データの書き込み → データのクエリ を行うだけです。以降のセクションでは、バッキング (ドキュメントを格納する基盤となるインデックス) の事前作成、スライスの事前登録、キャッシュのウォームアップの 3 つのタスクを任意としてマークしています。テナントをまとめてオンボードする前に、バッキングを事前作成し、スライスを登録してください。最初のクエリのレイテンシーが重要な場合は、まずキャッシュをウォームアップしてください。
インスタンスの準備
利用可能な Agent エンジンインスタンスが必要です。まだ作成していない場合は、まず 「Agent エンジンインスタンスの作成」 を完了してください。このトピックのリクエストは Kibana Dev Tools で実行します。使用するアカウントには、コレクションの管理権限とデータの読み取り/書き込み権限が必要です。詳細については、「Collection permissions」をご参照ください。
ステップ 1:コレクションの作成
コレクション knowledge-chunks を作成して、テナント識別子、タイトル、本文、ベクトルなどのフィールドを 1 か所にまとめて定義します。 トライアルとして、サンプルベクトルをそのまま使用できます。 実際のワークロードを接続する際は、ベクトル次元と類似性メトリックがモデルと一致するようにしてください。
PUT /_slice_collection/knowledge-chunks
{
"max_slices_per_shard": 200,
"settings": {
"index.number_of_shards": 2,
"index.number_of_replicas": 2
},
"mappings": {
"properties": {
"tenant_id": { "type": "keyword" },
"document_id": { "type": "keyword" },
"title": { "type": "text" },
"content": { "type": "text" },
"category": { "type": "keyword" },
"updated_at": { "type": "date" },
"embedding": {
"type": "dense_vector",
"dims": 4,
"index": true,
"similarity": "cosine",
"index_options": {
"type": "hnsw"
}
}
}
}
}レスポンスで acknowledged: true が返されることを確認します。これは、コレクション設定が作成されたことを示します。
システムはドキュメントを Backing (基盤となるインデックス) に保存し、1 つの Backing には複数の Slice を格納できます。max_slices_per_shard は、各 Backing が受け入れる新しい Slice の数を制御します。値を小さくすると、新しい Slice はより早く他の Backing の使用を開始します。このパラメーターは、単一の Slice 内のドキュメント数を制限するものではありません。容量計算については、「容量パラメーターがどのように有効になるか」をご参照ください。
バッキングの事前作成 (任意、推奨)
システムはオンデマンドでバッキングを作成するため、最初のトライアルではこのステップをスキップできます。テナントをまとめてオンボードしたり、データをインポートしたりする前に、5 つのバッキングを準備してください。バッキングを事前作成すると、最初の書き込み時のインデックス作成の待ち時間が短縮され、新しいテナントのデータが複数の基盤となるインデックスに分散されるため、読み取り/書き込み負荷の分散に役立ちます:
PUT /_slice_collection/knowledge-chunks/backings?count=5レスポンスで acknowledged: true が返され、backings に 5 つの名前がリストされていることを確認します。リクエストを再度実行すると、同じインデックスのセットがチェックされて完了しますが、その結果として既存のデータが再配布されることはありません。本番環境では、データ量とシャードリソースに基づいてカウントを調整してください。パラメーターと割り当てルールについては、「バッキングの事前作成」をご参照ください。
スライスの事前登録 (任意)
デフォルトでは、スライスは最初の書き込み時に自動的に登録されます。テナントをオンボードする際にビジネスデータパーティションを事前に登録すると、最初のビジネス書き込みから登録の待ち時間がなくなります:
PUT /_slice_collection/knowledge-chunks/slices
{
"slices": ["tenant-a", "tenant-b"]
}最上位の errors が false であり、各 items[].result が created または noop であることを確認してください。 created は新規登録を意味し、noop はスライスが既に存在し、変更が不要であることを意味します。 アイテムが failed の場合、データを書き込む前にそのエラーを解決してください。
ステップ 2:データの書き込み
通常の書き込みでは refresh を渡さず、アプリケーションコードで _refresh を呼び出さないでください。これらの操作は、データ公開、オブジェクトストレージの読み取り、およびクエリノードの更新のオーバーヘッドを大幅に増加させる可能性があります。refresh=wait_for は、頻度の低い同期ポイントでのみ使用し、まず適用条件とコストを確認してください。
Bulk 書き込み
1 つの Bulk リクエストを使用して、各テナントに 2 つのドキュメントを書き込みます。 2 つのテナントは同じ _id 値を使用しますが、ドキュメントの内容は異なります。 これにより、_id は同じスライス内でのみ一意である必要があり、異なるスライス間で ID を共有するドキュメントは互いに上書きされないことが検証されます。
POST /_bulk
{ "index": { "_index": "knowledge-chunks", "_id": "chunk-1001", "_slice": "tenant-a" } }
{ "tenant_id": "tenant-a", "document_id": "doc-refund-policy", "title": "Refund and return policy", "content": "You can request a refund for a duplicate purchase within seven days after the order is completed.", "category": "after-sales", "updated_at": "2026-07-30T10:00:00Z", "embedding": [0.82, 0.10, 0.05, 0.03] }
{ "index": { "_index": "knowledge-chunks", "_id": "chunk-1001", "_slice": "tenant-b" } }
{ "tenant_id": "tenant-b", "document_id": "doc-shipping-status", "title": "Track shipping status", "content": "Open the shipping information on the order details page to view the latest delivery status.", "category": "shipping", "updated_at": "2026-07-30T10:01:00Z", "embedding": [0.12, 0.78, 0.06, 0.04] }
{ "index": { "_index": "knowledge-chunks", "_id": "chunk-1002", "_slice": "tenant-a" } }
{ "tenant_id": "tenant-a", "document_id": "doc-change-address", "title": "Change the shipping address", "content": "Before the order is shipped, you can change the shipping address on the order details page.", "category": "orders", "updated_at": "2026-07-30T10:02:00Z", "embedding": [0.75, 0.16, 0.06, 0.03] }
{ "index": { "_index": "knowledge-chunks", "_id": "chunk-1002", "_slice": "tenant-b" } }
{ "tenant_id": "tenant-b", "document_id": "doc-invoice", "title": "Request electronic invoicing", "content": "After the order is completed, you can request electronic invoicing on the invoice management page.", "category": "billing", "updated_at": "2026-07-30T10:03:00Z", "embedding": [0.18, 0.70, 0.08, 0.04] }Bulk は NDJSON 形式を使用します。各オペレーションと各ドキュメントはそれぞれ 1 行を占め、リクエストボディの末尾には改行文字を付ける必要があります。Bulk リクエストでは、_slice はアクションメタデータの一部ですが、単一ドキュメントリクエストおよびクエリリクエストでは、URL クエリパラメーターです。レスポンスのトップレベルの errors が false であることを確認してください。一部のオペレーションが失敗した場合は、items 内のエラーを 1 つずつ検査し、解決してから続行してください。
書き込みレスポンスの _index 値は、.sc-* に一致する基盤となるインデックス名である場合があります。読み取りまたはクエリのレスポンスの _routing 値は、指定したビジネス Slice 名とは異なる、システムが生成した内部 Slice 識別子 (slice_uid) である場合があります。これは想定内の動作です。後続のリクエストでは、knowledge-chunks や tenant-a などのビジネス名を引き続き使用してください。これらの内部値を Collection 名または _slice パラメーターとして扱わず、そのフォーマットを解析しないでください。
ID による書き込みの検証 (任意)
GET は、デフォルトでリアルタイムにデータを読み取るため、通常は検索リフレッシュを待つ必要はありません。各テナントから chunk-1001 を読み取ります:
GET /knowledge-chunks/_doc/chunk-1001?_slice=tenant-aGET /knowledge-chunks/_doc/chunk-1001?_slice=tenant-b両方のレスポンスで found フィールドは true になり、タイトルは「返金および返品ポリシー」と「配送状況の追跡」になります。これにより、同じ ID を持つドキュメントが 2 つの Slice に別々に保存されていることが確認されます。プライマリシャードが利用できない場合の読み取り動作については、「ID による書き込みの検証」をご参照ください。
ステップ 3:テナント内でのデータクエリ
書き込みが成功したら、自動バックグラウンドリフレッシュでデータが検索可能になるまで約 5 秒待ってから、ウォームアップまたはクエリを実行してください。結果に新しいデータがまだ含まれていない場合は、ステップ 2 の「ID による書き込みの検証」のリアルタイム GET リクエストを使用して、ドキュメントが存在することを確認してください。その後、もう 1 回自動リフレッシュサイクルを待って再試行してください。データが検索可能になるまでの実際の時間は負荷にも依存するため、5 秒は完了を保証する時間ではありません。
クエリ対象スライスのウォームアップ (任意、推奨)
ウォームアップは、最初のクエリでオブジェクトストレージからコールドデータをロードする際の待機時間を短縮します。次のクエリは tenant-a をターゲットとするため、後続のクエリで再利用できるように、まずその検索可能なデータをクエリノードキャッシュにロードできます。この例では、結果を容易に確認できるように、同期的に待機します。
POST /knowledge-chunks/_warm_slice?_slice=tenant-a&wait_for_completion=true&timeout=60sリクエストが成功し、_shards.failed が 0 であることを確認します。この例ではデータがすでに書き込まれているため、_shards.total=0 は想定外です。その値が表示された場合は、まずクエリシャードが利用可能であることを確認し、実際のクエリを使用してデータが検索可能であることを確認してから、必要に応じてウォームアップを再試行します。タイムアウトまたはシャード障害が発生した場合は、再試行する前にエラーを調査します。ウォームアップは、その時点ですでに検索可能なデータのみを対象とし、後で追加されたデータは含まれません。
本番環境では、ユーザーがナレッジベースを選択したときなど、予測可能なアクセスポイントで事前にデータを非同期でウォームアップし、同時実行数を制御します。これにより、後続のクエリはキャッシュを再利用するため、クエリごとにウォームアップを待つ必要がありません。非同期の ACCEPTED レスポンスは、リクエストが送信されたことのみを意味します。結果を判断する方法については、「非同期ウォームアップの結果を判断する」をご参照ください。
ベクトル検索の実行
tenant-a 内のドキュメントのみをクエリし、ビジネス表示およびスコープ検証に使用されるフィールドを返します:
POST /knowledge-chunks/_search?_slice=tenant-a
{
"knn": {
"field": "embedding",
"query_vector": [0.80, 0.12, 0.05, 0.03],
"k": 10,
"num_candidates": 100
},
"_source": ["tenant_id", "document_id", "title", "content"]
}timed_out が false であり、_shards.failed が 0 であることを確認します。結果には「返金および返品ポリシー」と「配送先住所の変更」が含まれ、すべての結果の tenant_id は tenant-a である必要があります。URL 内の _slice を tenant-b に変更すると、結果は「配送状況の追跡」と「電子請求書の発行依頼」になります。2 つのテナントは同じドキュメント ID を使用するため、ID のみを比較するのではなく、テナントフィールドとタイトルでスコープを検証します。
tenant_id は表示と検証に使用される通常のフィールドであり、実際のクエリスコープは _slice によって決定されます。名前空間モードでは、デフォルトで明示的なスコープが必要であり、_slice を省略するとエラーが返されます。通常のビジネスクエリには _slice=_all を使用しないでください。マルチ Slice および全データクエリの適用条件については、「クエリスコープを指定する」をご参照ください。通常の検索ではベクトル値を取得する必要はありません。サーバーが KNN 計算を実行します。
次のステップ
テナントの一括オンボード、キャパシティ、ライフサイクル管理: Collection management。
単一ドキュメントの書き込み、一括読み取り、クエリ開発: Read and write data。
ベクトル検索の品質: Tune vector search results。
本番稼働の前に、「Limits」を確認し、「Collection permissions」で説明されているようにモニタリングと権限を設定してください。
オフラインクラスタリング完了後のクラスター選択: Automatically select candidate clusters。