セマンティック検索のウォークスルー

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に変更します。

このウォークスルーでは、事前トレーニング済モデルであるオプション1の使用方法を示します。
事前トレーニング済モデルを登録するには、次のものが必要です。

次の例に示すように、モデル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"
}

レジスタ操作のステータスを確認するには、次の例に示すように、タスクAPIGet操作で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"
}

レジスタ操作のステータスを確認するには、次の例に示すように、タスクAPIGet操作で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,