Recherche sémantique dans OpenSearch

La recherche OCI avec OpenSearch prend en charge la recherche sémantique commençant par OpenSearch version 2.11.

Avec la recherche sémantique, les moteurs de recherche utilisent le contexte et le contenu des requêtes de recherche pour mieux comprendre la signification d'une requête, par rapport à la recherche par mot clé, où les résultats de recherche sont basés sur le contenu correspondant aux mots clés d'une requête. OpenSearch met en oeuvre la recherche sémantique à l'aide de la recherche neuronale, technique qui utilise de grands modèles de langage pour comprendre les relations entre les termes. Pour plus d'informations sur la recherche neuronale dans OpenSearch, voir Tutoriel sur la recherche neuronale.

Utilisation de la recherche neuronale dans la recherche OCI avec OpenSearch

Pour utiliser la recherche neuronale pour la recherche sémantique dans la recherche OCI avec OpenSearch, vous devez :
  1. Enregistrer et déployer le modèle de votre choix dans la grappe.
  2. Créez un index et configurez un pipeline d'ingestion à l'aide du modèle déployé. Utilisez le pipeline d'ingestion pour ingérer des documents dans l'index.
  3. Exécuter des interrogations de recherche sémantique sur l'index à l'aide de la recherche hybride ou de la recherche neuronale.

Préalables

Pour utiliser la recherche sémantique, la version OpenSearch de la grappe doit être 2.11 ou plus récente. Par défaut, les nouvelles grappes utilisent la version 2.11. Voir Création d'une grappe OpenSearch.

Pour les grappes existantes configurées pour la version 2.3, vous pouvez effectuer une mise à niveau en ligne vers la version 2.11. Pour plus d'informations, voir Mises à niveau du logiciel de grappe OpenSearch.

Pour mettre à niveau les grappes existantes configurées pour la version 1.2.3 vers la version 2.11, vous devez utiliser le processus de mise à niveau décrit dans Mises à niveau du logiciel de grappe OpenSearch.

Avant de commencer à configurer le modèle pour la recherche sémantique, vous devez remplir les préalables, notamment spécifier la politique IAM applicable si nécessaire et configurer les paramètres de grappe recommandés.

Politique du service IAM pour les modèles personnalisés et les connecteurs d'IA générative

Si vous utilisez l'un des modèles préentraînés hébergés dans le service de recherche pour OCI avec OpenSearch, vous n'avez pas besoin de configurer les autorisations, vous pouvez passer à la condition préalable suivante, Paramètres de grappe pour la recherche sémantique. Voir aussi Présentation sur la recherche sémantique.

Sinon, vous devez créer une politique pour accorder l'accès requis.

Vous devez créer une politique pour accorder l'accès requis.

Pour en connaître davantage sur les politiques, voir Introduction aux politiques et Politiques communes.

Politique IAM pour les modèles personnalisés

Si vous utilisez un modèle personnalisé, vous devez accorder l'accès à la recherche OCI avec OpenSearch pour accéder au seau de stockage d'objets qui contient le modèle.

L'exemple de politique suivant inclut l'autorisation requise :

ALLOW ANY-USER to manage object-family in tenancy WHERE ALL {request.principal.type='opensearchcluster', request.resource.compartment.id='<cluster_compartment_id>'}

Politique du service IAM pour les connecteurs d'IA générative

Si vous utilisez un connecteur d'IA générative, vous devez accorder l'accès à la recherche OCI avec OpenSearch pour accéder aux ressources d'IA générative.

L'exemple de politique suivant inclut l'autorisation requise :

ALLOW ANY-USER to manage generative-ai-family in tenancy WHERE ALL {request.principal.type='opensearchcluster', request.resource.compartment.id='<cluster_compartment_id>'}

Régions pour les connecteurs du service d'intelligence artificielle générative

Pour utiliser le service d'intelligence artificielle générative pour OCI, votre location doit être abonnée à la région Midwest des États-Unis (Chicago) ou à la région Centre de l'Allemagne (Francfort). Vous n'avez pas besoin de créer la grappe dans l'une ou l'autre de ces régions. Assurez-vous simplement que votre location est abonnée à l'une des régions.

Paramètres de grappe pour la recherche sémantique

Utilisez l'opération paramètres des API de grappe pour configurer les paramètres de grappe recommandés pour la recherche sémantique. L'exemple suivant présente les paramètres recommandés :

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
      }
    }
  }
}

Configuration d'un modèle

La première étape lors de la configuration de la recherche neuronale consiste à configurer le grand modèle de langage que vous souhaitez utiliser. Le modèle est utilisé pour générer des plongements vectoriels à partir de champs de texte.

Enregistrer un groupe de modèles

Les groupes de modèles permettent de gérer l'accès à des modèles spécifiques. L'enregistrement d'un groupe de modèles est facultatif. Toutefois, si vous n'enregistrez pas de groupe de modèles, ML Commons crée un nouveau groupe de modèles pour vous. Nous vous recommandons donc d'enregistrer le groupe de modèles.

Enregistrez un groupe de modèles à l'aide de l'opération Enregistrer dans les API de groupe de modèles, comme illustré dans l'exemple suivant :

POST /_plugins/_ml/model_groups/_register
{
  "name": "new_model_group",
  "description": "A model group for local models"
}

Notez la valeur model_group_id retournée dans la réponse :

{
  "model_group_id": "<model_group_ID>",
  "status": "CREATED"
}

Enregistrer le modèle dans le groupe de modèles

Enregistrez le modèle à l'aide de l'opération Enregistrer à partir des API de modèle. Le contenu de la demande POST pour l'opération d'enregistrement dépend du type de modèle que vous utilisez.

  • Option 1 : Modèles préentraînés OpenSearch intégrés

    Plusieurs modèles de transformateur de phrase préentraînés sont disponibles pour vous permettre d'enregistrer et de déployer directement dans une grappe sans avoir à les télécharger, puis de les charger manuellement dans un seau de stockage privé, contrairement au processus requis pour l'option de modèles personnalisés. Avec cette option, lorsque vous enregistrez un modèle préentraîné, vous n'avez besoin que des valeurs model_group_id, name, version et model_format du modèle. Voir Utilisation d'un modèle préentraîné OpenSearch pour savoir comment utiliser un modèle préentraîné.

  • Option 2 : Modèles personnalisés

    Vous devez transmettre l'URL du stockage d'objets dans la section actions de l'opération d'enregistrement, par exemple :

    POST /_plugins/_ml/models/_register
    {
    .....
            "actions": [
                {
                    "method": "GET",
                    "action_type": "DOWNLOAD",
                    "url": "<object_storage_URL_path>"
                }
            ]
        }
    }

    Pour un exemple complet d'opération d'enregistrement, voir Modèles personnalisés - 2 : Enregistrer le modèle.

  • Option 3 : Connecteur d'IA générative

    Vous pouvez également enregistrer et déployer un modèle d'intégration GenAI distant tel que cohere.embed-english-v3.0 dans votre grappe à l'aide de notre connecteur GenAI. Vous devez d'abord créer un connecteur, puis enregistrer et déployer le modèle à l'aide de l'ID connecteur, comme décrit dans les étapes suivantes.

    Note

    Si vous utilisez le modèle ON-DEMAND, restez à jour avec les avis d'abandon de modèle du service GenAI et mettez à jour votre connecteur si nécessaire pour éviter d'éventuelles interruptions de service. Voir Modèles fondamentaux préentraînés dans l'intelligence artificielle générative pour les modèles d'intégration pris en charge afin de sélectionner un modèle d'intégration dans la liste des modèles pris en charge.

    Si vous utilisez le modèle DEDICATED, remplacez le paramètre servingType dans l'exemple de données utiles suivant ON-DEMAND par DEDICATED.

    Créez un connecteur pour le modèle Cohere Embedding :

    POST /_plugins/_ml/connectors/_create
    {
      "name": "<connector_name>",
      "description": "<connector_description>",
      "version": "2",
      "protocol": "oci_sigv1",
      
        "parameters": {
          "endpoint": "inference.generativeai.us-chicago-1.oci.oraclecloud.com",
          "auth_type": "resource_principal",
          "model": "<embedding_model>",
          "input_type":"search_document",
          "truncate": "END"
        },
      
         "credential": {
         },
         "actions": [
             {
                 "action_type": "predict",
                 "method":"POST",
                 "url": "https://${parameters.endpoint}/20231130/actions/embedText",
                 "request_body": "{ \"inputs\":[\"${parameters.passage_text}\"], \"truncate\": \"${parameters.truncate}\" ,\"compartmentId\": \"<compartment_ocid>\", \"servingMode\": { \"modelId\": \"${parameters.model}\", \"servingType\": \"ON_DEMAND\" } }",
                 "pre_process_function": "return '{\"parameters\": {\"passage_text\": \"' + params.text_docs[0] + '\"}}';",
                  "post_process_function": "connector.post_process.cohere.embedding"
             }
         ]
     }

    L'exemple suivant présente des données utiles pour créer un connecteur pour le modèle cohere.embed-english-v3.0 :

    POST /_plugins/_ml/connectors/_create
    {
      "name": "OCI GenAI Chat Connector to cohere.embed-english-v3 model",
      "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-english-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\":[\"${parameters.passage_text}\"], \"truncate\": \"${parameters.truncate}\" ,\"compartmentId\": \"ocid1.compartment.oc1..aaaaaaaa..........5bynxlkea\", \"servingMode\": { \"modelId\": \"${parameters.model}\", \"servingType\": \"ON_DEMAND\" } }",
                 "pre_process_function": "return '{\"parameters\": {\"passage_text\": \"' + params.text_docs[0] + '\"}}';",
                  "post_process_function": "connector.post_process.cohere.embedding"
             }
         ]
     }

Après avoir effectué la demande d'enregistrement, vous pouvez vérifier le statut de l'opération, utiliser task_id avec l'opération Obtenir des API de tâches, comme illustré dans l'exemple suivant :

GET /_plugins/_ml/tasks/<task_ID>

Une fois l'opération d'enregistrement terminée, la valeur status dans la réponse à l'opération Get est COMPLETED, comme illustré dans l'exemple suivant :

{
  "model_id": "<embedding_model_ID>",
  "task_type": "REGISTER_MODEL",
  "function_name": "TEXT_EMBEDDING",
  "state": "COMPLETED",
  "worker_node": [
    "3qSqVfK2RvGJv1URKfS1bw"
  ],
  "create_time": 1706829732915,
  "last_update_time": 1706829780094,
  "is_async": true
}

Notez la valeur model_id retournée dans la réponse à utiliser lors du déploiement du modèle.

Déployer le modèle

Une fois l'opération d'enregistrement terminée pour le modèle, vous pouvez déployer le modèle dans la grappe à l'aide de l'opération de déploiement des API de modèle, en transmettant model_id à partir de la réponse de l'opération Get à l'étape précédente, comme illustré dans l'exemple suivant :

POST /_plugins/_ml/models/<embedding_model_ID>/_deploy

Notez la valeur task_id retournée dans la réponse. Vous pouvez utiliser task_id pour vérifier le statut de l'opération.

Par exemple, à partir de la réponse suivante :

{
  "task_id": "<task_ID>",
  "task_type": "DEPLOY_MODEL",
  "status": "CREATED"
}

pour vérifier le statut de l'opération d'enregistrement, utilisez task_id avec l'opération Obtenir des API de tâches, comme illustré dans l'exemple suivant :

GET /_plugins/_ml/tasks/<task_ID>

Une fois l'opération de déploiement terminée, la valeur status dans la réponse à l'opération Get est COMPLETED.

Ingérer les données

La première étape lors de la configuration de la recherche neuronale consiste à configurer le grand modèle de langage que vous souhaitez utiliser. Le modèle est utilisé pour générer des plongements vectoriels à partir de champs de texte.

Ingérer les données dans l'index

Après avoir créé un index, vous pouvez désormais ingérer des données dans l'index, comme illustré dans l'exemple suivant :

POST /test-index/_doc/1
{
  "passage_text": "there are many sharks in the ocean"
}
 
POST /test-index/_doc/2
{
  "passage_text": "fishes must love swimming"
}
 
POST /test-index/_doc/3
{
  "passage_text": "summers are usually very hot"
}
 
POST /test-index/_doc/4
{
  "passage_text": "florida has a nice weather all year round"
}
Utilisez un GET pour vérifier que les documents sont ingérés correctement et que les intégrations sont générées automatiquement lors de l'ingestion :
GET /test-index/_doc/3

Créer un pipeline d'ingestion

À l'aide de l'ID modèle du modèle déployé, créez un pipeline d'ingestion, comme illustré dans l'exemple suivant :

PUT _ingest/pipeline/test-nlp-pipeline
{
  "description": "An example neural search pipeline",
  "processors" : [
    {
      "text_embedding": {
        "model_id": "<model_ID>",
        "field_map": {
           "passage_text": "passage_embedding"
        }
      }
    }
  ]
}

Le pipeline d'ingestion définit un processeur et les mappages de champ (dans ce cas, "passage_text" → "passage_embedding" ) Cela signifie que si vous utilisez ce pipeline sur un index spécifique pour ingérer des données, le pipeline trouve automatiquement le champ "passage_text" et utilise le modèle de pipeline pour générer les intégrations correspondantes, "passage_embedding", puis les mappe avant l'indexation.

N'oubliez pas que "passage_text" → "passage_embedding" sont définis par l'utilisateur et peuvent être ce que vous voulez. Assurez-vous d'être cohérent avec l'attribution de nom lors de la création de l'index où vous prévoyez d'utiliser le pipeline. Le processeur de pipeline doit pouvoir mapper les champs comme décrit.

Créer un index

Lors de la création de l'index, vous pouvez spécifier le pipeline à utiliser pour ingérer des documents dans l'index.

L'exemple d'appel d'API suivant montre comment créer un index à l'aide du pipeline test-nlp-pipeline créé à l'étape précédente.

PUT /test-index
{
    "settings": {
        "index.knn": true,
        "default_pipeline": "test-nlp-pipeline"
    },
    "mappings": {
        "properties": {
            "passage_embedding": {
                "type": "knn_vector",
                "dimension": <model_dimension>,
                "method": {
                    "name":"hnsw",
                    "engine":"lucene",
                    "space_type": "l2",
                    "parameters":{
                        "m":512,
                        "ef_construction": 245
                    }
                }
            },
            "passage_text": {
                "type": "text"
            }
        }
    }
}

Lors de la création de l'index, vous devez également spécifier l'implémentation de bibliothèque du voisin le plus proche approximatif (ANN) que vous souhaitez utiliser. OCI Search with OpenSearch prend en charge les bibliothèques NMSLIB, Faiss et Lucene. Pour plus d'informations, voir Moteurs de recherche.

L'exemple suivant utilise le moteur Lucene :

{
  "model_id": "<model_ID>",
  "task_type": "REGISTER_MODEL",
  "function_name": "TEXT_EMBEDDING",
  "state": "COMPLETED",
  "worker_node": [
    "3qSqVfK2RvGJv1URKfS1bw"
  ],
  "create_time": 1706829732915,
  "last_update_time": 1706829780094,
  "is_async": true
}

Ingérer les données dans l'index

Après avoir créé un index, vous pouvez désormais ingérer des données dans l'index, comme illustré dans l'exemple suivant :

POST /test-index/_doc/1
{
  "passage_text": "there are many sharks in the ocean"
}
 
POST /test-index/_doc/2
{
  "passage_text": "fishes must love swimming"
}
 
POST /test-index/_doc/3
{
  "passage_text": "summers are usually very hot"
}
 
POST /test-index/_doc/4
{
  "passage_text": "florida has a nice weather all year round"
}

Utilisez un GET pour vérifier que les documents sont ingérés correctement et que les intégrations sont générées automatiquement lors de l'ingestion :

GET /test-index/_doc/3