セマンティック検索のウォークスルー
OCI SearchでOpenSearchを使用してデータのセマンティック検索を実行する方法について学習します。
前提条件
開始する前に、次のことを行う必要があります。
-
OCI Searchでサポートされている事前トレーニング済モデルの1つをOpenSearchで選択します
-
OpenSearchクラスタがバージョン2.11であることを確認します。
-
セマンティック検索を実行するようにクラスタ設定を更新します。次のコマンド例では、適用可能な設定を更新します。
PUT _cluster/settings { "persistent": { "plugins": { "ml_commons": { "only_run_on_ml_node": "false", "model_access_control_enabled": "true", "native_memory_threshold": "99", "rag_pipeline_feature_enabled": "true", "memory_feature_enabled": "true", "allow_registering_model_via_local_file": "true", "allow_registering_model_via_url": "true", "model_auto_redeploy.enable":"true", "model_auto_redeploy.lifetime_retry_times": 10 } } } }
モデル・グループの登録
モデル・グループを使用して、モデルを論理的にグループ化し、アクセスするユーザーを制御します。次の例に示すように、モデル・グループAPIの登録操作を使用してモデル・グループを登録します。
POST /_plugins/_ml/model_groups/_register
{
"name": "general pretrained models",
"description": "A model group for pretrained models hosted by OCI Search with OpenSearch"
}
レスポンスで返されたmodel_group_id
を書き留めます。
{
"model_group_id": "<model_group_ID>",
"status": "CREATED"
}
モデルの登録およびデプロイ
セマンティック検索には、次の3つのオプションがあります。
- オプション1: 「OpenSearch事前トレーニング済モデルの使用」で説明されているステップを使用して、OCI Searchでホストされている事前トレーニング済モデルをOpenSearchに登録してデプロイします。このオプションは最も簡単に使用でき、追加のIAMポリシーを構成する必要はなく、ペイロードは次のオプションのペイロードほど複雑ではありません。
- オプション2: カスタム・モデルで説明されているステップを使用して、OpenSearch事前トレーニング済モデルをインポート、登録およびデプロイします。これには、オブジェクト・ストレージ・バケットへのモデル・ファイルのアップロード、およびモデルの登録時にモデル・ファイルのオブジェクト・ストレージURLの指定が含まれます。
- オプション3: GenAIコネクタを使用して、リモートのGenAI埋込みモデル(cohere.embed-english-v3.0など)をクラスタに登録およびデプロイすることもできます。最初にコネクタを作成し、次のステップの説明に従ってコネクタIDを使用してモデルを登録およびデプロイする必要があります。ノート
ON-DEMANDモデルを使用している場合は、GenAIサービスからのモデル非推奨通知を最新の状態に保ち、サービスの中断の可能性を回避するために、必要に応じてコネクタを更新します。サポートされている埋込みモデルで、サポートされているモデルのリストから埋込みモデルを選択するには、生成AIの事前トレーニング済基本モデルを参照してください。DEDICATEDモデルを使用している場合は、次のペイロード例の
servingType
パラメータをON-DEMANDからDEDICATEDに変更します。
model_group_id
: ステップ1を完了した場合、これは_registerリクエストに対するmodel_group_idの値です。name
: 使用する事前トレーニング済モデルのモデル名。version
: 使用する事前トレーニング済モデルのバージョン番号。model_format
: モデルの形式(TORCH_SCRIPT
またはONNX
)。
次の例に示すように、モデルAPIの登録操作を使用してモデルを登録します。
POST /_plugins/_ml/models/_register
{
"name": "huggingface/sentence-transformers/msmarco-distilbert-base-tas-b",
"version": "1.0.2",
"model_group_id": "<model_group_ID>",
"model_format": "TORCH_SCRIPT"
}
レスポンスで返されたtask_id
を書き留めます。task_id
を使用して、操作のステータスを確認できます。
たとえば、次のレスポンスから:
{
"task_id": "<task_ID>",
"status": "CREATED"
}
レジスタ操作のステータスを確認するには、次の例に示すように、タスクAPIのGet操作でtask_id
を使用します。
GET /_plugins/_ml/tasks/<task_ID>
登録操作が完了すると、次の例に示すように、Get操作に対するレスポンスのstate
値はCOMPLETED
になります。
{
"model_id": "<embedding_model_ID>",
"task_type": "REGISTER_MODEL",
"function_name": "TEXT_EMBEDDING",
"state": "COMPLETED",
"worker_node": [
"f2b_8-mVRVyVqeKqsA7dcQ"
],
"create_time": 1706831015570,
"last_update_time": 1706831070740,
"is_async": true
}
モデルのデプロイ時に使用するレスポンスで返されるmodel_ID
値をノートにとります。
モデルのデプロイ
モデルの登録操作が完了したら、次の例に示すように、モデルAPIのdeploy操作を使用して、前のステップでGet操作レスポンスからmodel_ID
を渡して、モデルをクラスタにデプロイできます。
POST /_plugins/_ml/models/<embedding_model_ID>/_deploy
レスポンスで返されたtask_id
を書き留めます。task_id
を使用して、操作のステータスを確認できます。
たとえば、次のレスポンスから:
{
"task_id": "<task_ID>",
"task_type": "DEPLOY_MODEL",
"status": "CREATED"
}
レジスタ操作のステータスを確認するには、次の例に示すように、タスクAPIのGet操作でtask_ID
を使用します。
GET /_plugins/_ml/tasks/<task_ID>
デプロイ操作が完了すると、Get操作に対するレスポンスのstatus
値はCOMPLETED
になります。
k-NN取込みパイプラインの作成
デプロイ操作が完了したら、デプロイされたモデルを使用して取込みパイプラインを作成します。取込みパイプラインでは、デプロイされたモデルを使用して、取込み時に各ドキュメントの埋込みベクトルを自動的に生成します。プロセッサは埋込みのすべてを処理するため、埋込みに変換されるドキュメントの必要なテキスト・フィールドを適切にマップするだけで済みます。次の例は、取込みパイプラインの作成を示しています。
PUT _ingest/pipeline/<pipeline_name>
{
"description": "An example neural search pipeline",
"processors" : [
{
"text_embedding": {
"model_id": "<embedding_model_ID>",
"field_map": {
"<text_field_name>": "<embedding_field_name>"
}
}
}
]
}
取込みパイプラインが作成された場合は、次のレスポンスが返されます。
{
"acknowledged": true
}
索引の作成
前のステップで作成した取込みパイプラインを使用して索引を作成します。索引内の使用可能なANNエンジンを使用できます。次の例では、Lucene Engineを使用します。
PUT /lucene-index
{
"settings": {
"index.knn": true,
"default_pipeline": "<pipeline_name>"
},
"mappings": {
"properties": {
"<embedding_field_name>": {
"type": "knn_vector",
"dimension": <model_dimension>,
"method": {
"name":"hnsw",
"engine":"lucene",
"space_type": "l2",
"parameters":{
"m":512,
"ef_construction": 245
}
}
},
"<text_field_name>": {
"type": "text"
}
}
}
}
インデックスの作成のpassage_text
フィールドは、取込みパイプラインのpassage_text
フィールドと一致するため、パイプラインは埋込みの作成方法を知り、取込み時にドキュメントにマップできます。
使用するエンジンおよびそれらのエンジンで使用可能な構成パラメータの選択に役立つように、k-NN indexおよびApproximate k-NN searchを参照してください。
索引作成の成功に対するレスポンスの例を次に示します。
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "lucene-index"
}
索引へのドキュメントの取込み
次の例に示すように、インデックスにデータを取り込みます。
POST /lucene-index/_doc/1
{
"<text_field_name>": "there are many sharks in the ocean"
}
POST /lucene-index/_doc/2
{
"<text_field_name>": "fishes must love swimming"
}
POST /lucene-index/_doc/3
{
"<text_field_name>": "summers are usually very hot"
}
POST /lucene-index/_doc/4
{
"<text_field_name>": "florida has a nice weather all year round"
}
レスポンス:
# POST /lucene-index/_doc/1
{
"_index": "lucene-index",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
# POST /lucene-index/_doc/2
{
"_index": "lucene-index",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}
# POST /lucene-index/_doc/3
{
"_index": "lucene-index",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1
}
# POST /lucene-index/_doc/4
{
"_index": "lucene-index",
"_id": "4",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
次の手順を実行して、ドキュメントの1つをチェックし、埋込みが正しく生成されていることを確認します。
GET /lucene-index/_doc/3
レスポンス:
{
"_index": "lucene-index",
"_id": "3",
"_version": 1,
"_seq_no": 2,
"_primary_term": 1,
"found": true,
"_source": {
"<embedding_field_list>": [
-0.1254959,
-0.3151774,
0.03526799,
0.39322096,
-0.0475556,
-0.12378334,
-0.032554347,
0.4033895,
0.050718695,
-0.3587931,
0.097042784,
0.11742551,
-0.06573639,
0.14252506,
-0.466573,
0.56093556,
-0.2815812,
-0.00016521096,
-0.2858566,
セマンティック検索の実行
この項では、実行できる様々なタイプのセマンティック検索の例を示します。
ハイブリッド検索によるセマンティック検索
「モデルの登録およびデプロイ」のモデルIDを使用して、次のようにハイブリッド検索を使用してセマンティック検索を実行します:
GET lucene-index/_search
{
"query": {
"bool" : {
"should" : [
{
"script_score": {
"query": {
"neural": {
"<embedding_field_name>": {
"query_text": "what are temperatures in miami like",
"model_id": "<embedding_model_ID>",
"k": 2
}
}
},
"script": {
"source": "_score * 1.5"
}
}
}
]
}
},
"fields": [
"<text_field_name>"
],
"_source": false
}
レスポンス:
{
"took": 343,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.032253794,
"hits": [
{
"_index": "lucene-index",
"_id": "4",
"_score": 0.032253794,
"fields": {
"<text_field_name>": [
"florida has a nice weather all year round"
]
}
},
{
"_index": "lucene-index",
"_id": "3",
"_score": 0.031487543,
"fields": {
"<text_field_name>": [
"summers are usually very hot"
]
}
}
]
}
}
問合せの質問にFlorida、weatherおよびsummerは記載されていないことがわかりますが、モデルは最も関連性の高い回答を返すtemperaturesおよびmiamiのセマンティックな意味を推測します。
ニューラル検索によるセマンティック検索
「モデルの登録およびデプロイ」のモデルIDを使用して、次のようにニューラル検索を使用してセマンティック検索を実行します:
GET /lucene-index/_search
{
"_source": {
"excludes": [
"<embedding_field_name>"
]
},
"query": {
"neural": {
"<embedding_field_name>": {
"query_text": "good climate",
"model_id": "<embedding_model_ID>",
"k": 5
}
}
}
}
レスポンス:
{
"took": 36,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 0.012060728,
"hits": [
{
"_index": "lucene-index",
"_id": "4",
"_score": 0.012060728,
"_source": {
"passage_text": "florida has a nice weather all year round"
}
},
{
"_index": "lucene-index",
"_id": "1",
"_score": 0.010120423,
"_source": {
"passage_text": "there are many sharks in the ocean"
}
},
{
"_index": "lucene-index",
"_id": "3",
"_score": 0.00985171,
"_source": {
"passage_text": "summers are usually very hot"
}
},
{
"_index": "lucene-index",
"_id": "2",
"_score": 0.009575767,
"_source": {
"passage_text": "fishes must love swimming"
}
}
]
}
}