はじめに
OCI Search with OpenSearchでは、OpenSearchバージョン2.11以降のセマンティク検索がサポートされています。
こちらの記事ではOpenSearchに組み込まれている事前トレーニング済モデルを使用したセマンティック検索を実施してみました。今回はOCI Generative AIを使用して行ってみました。
前提条件
- OpenSearchバージョンが2.11以降のOpenSearchクラスタのプロビジョニング
- OpenSearch ダッシュボードへのアクセス
- 作業は OpenSearch ダッシュボードの Dev Toolsを使って実行
作業ステップ
- 事前準備
- ステップ1 モデル・グループの登録
- ステップ2 コネクタの作成
- ステップ3 モデルのモデル・グループへの登録
- ステップ4 モデルのデプロイ
- ステップ5 Ingestionパイプラインの作成
- ステップ6 インデックスの作成
- ステップ7 ドキュメントの取り込み
- ステップ8 Embeddingが正しく生成されていることを確認
- セマンティック検索の実行
実行例
OpenSearchからOGI Generative AIサービスへアクセスするためのリソース・プリンシパルの設定
opensearchクラスタがGenerative AI リソースへのアクセスを許可するようにIAMポリシーを構成します。(リソース・プリンシパルの設定)
ALLOW ANY-USER to manage generative-ai-family in tenancy WHERE ALL {request.principal.type='opensearchcluster',request.resource.compartment.id='< cluster_compartment_id >'}
< cluster_compartment_id >にOCI Search with OpenSearchクラスタが存在するコンパートメントIDを指定します。
セマンティック検索を実行できるようにクラスタ設定を更新
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
}
}
}
}
ステップ1 モデル・グループの登録
特定のモデルへのアクセスを管理するモデル・グループを作成します。
モデル・グループの登録APIの実行
POST /_plugins/_ml/model_groups/_register
{
"name": "general pretrained models",
"description": "A model group for models of OCI Gen AI"
}
レスポンスで返されたmodel_group_idを記録します。
{
"model_group_id": "SGkEvI4BapwKtdhKEyeT",
"status": "CREATED"
}
ステップ2 コネクタの作成
OCI Generative AIを利用するためのコネクタを作成します。
認証方式、利用するモデル、OpenSearchクラスタの存在するコンパートメントのOCIDをパラメータ入力します。
POST _plugins/_ml/connectors/_create
{
"name": "OCI GenAI Connector cohere-embed",
"description": "The connector to public Cohere model service for embed",
"version": "2",
"protocol": "oci_sigv1",
"parameters": {
"endpoint": "inference.generativeai.us-chicago-1.oci.oraclecloud.com",
"auth_type": "resource_principal",
"model": "cohere.embed-multilingual-v3.0",
"input_type":"search_document",
"truncate": "END"
},
"credential": {
},
"actions": [
{
"action_type": "predict",
"method":"POST",
"url": "https://${parameters.endpoint}/20231130/actions/embedText",
"request_body": "{ \"inputs\": [\"${passage_text}\"],
\"truncate\":\"${parameters.truncate}\" , \"compartmentId\":\"< cluster_compartment_id >\",
\"servingMode\": { \"modelId\": \"${parameters.model}\", \"servingType\":\"ON_DEMAND\" } }",
"pre_process_function": "connector.pre_process.cohere.embedding",
"post_process_function": "connector.post_process.cohere.embedding"
}
]
}
この例では
- 認証方式にリソースプリンシパル ( resource_principal )
- 利用するモデルに cohere.embed-multilingual-v3.0
- < cluster_compartment_id > に OpenSearchクラスタの存在するコンパートメントのOCID
を指定します。
レスポンスで返されたconnector_idを記録します。
{
"connector_id": "hGmF244BapwKtdhKTyca"
}
ステップ3 モデルのモデル・グループへの登録
コネクタを使用するモデルを登録します。以下の情報を入力します。
- model_group_id: 登録するモデル・グループのmodel_group_id (SGkEvI4BapwKtdhKEyeT)
- connector_id: 作成したコネクタのconnector_id (hGmF244BapwKtdhKTyca)
- 名前: 使用する事前トレーニング済モデルのモデル名
- Function_name: リモート
- description: モデルの説明
モデルの登録例
POST /_plugins/_ml/models/_register
{
"name": "oci-genai-embedding",
"function_name": "remote",
"model_group_id": "SGkEvI4BapwKtdhKEyeT",
"description": "cohere multilingual embedding model",
"connector_id": "hGmF244BapwKtdhKTyca"
}
レスポンスで返されたtask_idを記録
{
"task_id": "heyif40BJxmKsWKUbBae",
"status": "CREATED",
"model_id": "hmmG244BapwKtdhKjScY"
}
task_id (heyif40BJxmKsWKUbBae)を使用してモデル登録のステータスを確認
GET /_plugins/_ml/tasks/heyif40BJxmKsWKUbBae
レスポンスのステータスがCOMPLETEDになっていることを確認し、レスポンスで返されたmodel_idを記録します。
{
"model_id": "hmmG244BapwKtdhKjScY",
"task_type": "REGISTER_MODEL",
"function_name": "TEXT_EMBEDDING",
"state": "COMPLETED",
"worker_node": [
"0Hic_MLcR1WQhLq3zCgMuw"
],
"create_time": 1712552074058,
"last_update_time": 1712552118631,
"is_async": true
}
ステップ4 モデルのデプロイ
パイプラインからモデルを利用できるようにmodel_id (hmmG244BapwKtdhKjScY)を指定してモデルをクラスタにデプロイします。
POST /_plugins/_ml/models/hmmG244BapwKtdhKjScY/_deploy
レスポンスでステータスが"COMPLETED"になっていることを確認します。
{
"task_id": "h2mH244BapwKtdhKGicD",
"task_type": "DEPLOY_MODEL",
"status": "COMPLETED"
}
ステップ5 Ingestionパイプラインの作成
デプロイされたモデルを使用してIngestionパイプラインを作成します。
- Ingestionパイプラインは、デプロイされたモデルを使用して、データ取込み時に各ドキュメントのEmbedベクトルを自動的に生成します。
- ベクトル化するテキストフィールドをマッピングするだけします。
- パイプラインとデプロイされたモデルのmodel_idを指定します。
Ingestionパイプラインの作成例
PUT _ingest/pipeline/pipeline_name01
{
"description": "An example neural search pipeline",
"processors" : [
{
"text_embedding": {
"model_id": "hmmG244BapwKtdhKjScY",
"field_map": {
"field_name01": "embedding_field_name01"
}
}
}
]
}
{
"acknowledged": true
}
ステップ6 インデックスの作成
作成したIngestionパイプラインを使用し、セマンティック検索で使用するANNエンジンを指定し、インデックスを作成します。
Lucene Engineを使用したインデックス作成の例
- パイプライン名、ANNエンジンを指定します。
- Embeddingモデルのディメンションを適切に指定します。
- IngestionパイプラインとEmbeddingフィールドを指定することで、パイプラインはEmbeddingの作成方法を認識し、取込み時にドキュメントにEmbeddingし結果を格納します。
PUT /lucene-index
{
"settings": {
"index.knn": true,
"default_pipeline": "pipeline_name01"
},
"mappings": {
"properties": {
"embedding_field_name01": {
"type": "knn_vector",
"dimension": 1024,
"method": {
"name":"hnsw",
"engine":"lucene",
"space_type": "l2",
"parameters":{
"m":512,
"ef_construction": 245
}
}
},
"field_name01": {
"type": "text"
}
}
}
}
索引が正常に作成された場合のレスポンス
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "lucene-index"
}
ステップ7 ドキュメントの取り込み
データをインデックスに取り込みます。(4件)
POST /lucene-index/_doc/1
{
"field_name01": "there are many sharks in the ocean"
}
レスポンス
{
"_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
{
"field_name01": "fishes must love swimming"
}
レスポンス
{
"_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
{
"field_name01": "summers are usually very hot"
}
レスポンス
{
"_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
{
"field_name01": "florida has a nice weather all year round"
}
レスポンス
{
"_index": "lucene-index",
"_id": "4",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}
( そのほかの データも格納しました。)
ステップ8 Embeddingが正しく生成されていることを確認
Embeddingが正しくされていることを確認します
GET /lucene-index/_doc/3
レスポンス
{
"_index": "lucene-index",
"_id": "3",
"_version": 1,
"_seq_no": 2,
"_primary_term": 1,
"found": true,
"_source": {
"embedding_field_name01": [
-0.12549585,
-0.31517762,
0.03526806,
0.39322084,
-0.04755569,
-0.12378363,
-0.032554734,
以下略
セマンティック検索の実行
- 登録しデプロイしたモデルIDを使用して、
セマンティック検索を実行
GET /lucene-index/_search
{
"_source": {
"excludes": [
"embedding_field_name01"
]
},
"query": {
"neural": {
"embedding_field_name01": {
"query_text": "Cars",
"model_id": "hmmG244BapwKtdhKjScY",
"k": 5
}
}
}
}
「Cars」のキーワードで検索した結果
- Porsches
- Toyota
- Ford
- Nissan
- Volvo
の文字が含まれた文が返されました。
{
"hits": {
"total": {
"value": 5,
"relation": "eq"
},
"max_score": 0.01621401,
"hits": [
{
"_index": "lucene-index","_id": "40","_score": 0.01621401,
"_source": {
"field_name01": "Porsches are fast and reliable."
}
},
{
"_index": "lucene-index","_id": "38","_score": 0.014877659,
"_source": {
"field_name01": "Toyotas are reliable."
}
},
{
"_index": "lucene-index","_id": "35","_score": 0.014761,
"_source": {
"field_name01": "Ford 150 are popular."
}
},
{
"_index": "lucene-index","_id": "41","_score": 0.014484754,
"_source": {
"field_name01": "Nissan GTRs are great."
}
},
{
"_index": "lucene-index","_id": "37","_score": 0.014443698,
"_source": {
"field_name01": "Volvos are safe."
}
}
]
}
おわりに
OCI Generative AIを使ってベクトル生成し、OpenSearch 2.11 でセマンティック検索ができました。