Recherche sémantique dans OpenSearch

OCI Search avec OpenSearch prend en charge la recherche sémantique à partir de 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 des mots-clés de correspondance de contenu dans une requête. OpenSearch implémente la recherche sémantique à l'aide de la recherche neuronale, une 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, reportez-vous au tutoriel de recherche neuronale.

Utilisation de la recherche neurale dans OCI Search avec OpenSearch

Pour utiliser la recherche neuronale pour la recherche sémantique dans OCI Search avec OpenSearch, vous devez :
  1. Enregistrez et déployez le modèle de votre choix dans le cluster.
  2. Créez un index et configurez un pipeline d'inclusion à l'aide du modèle déployé. Utilisez le pipeline d'inclusion pour inclure des documents dans l'index.
  3. Exécutez des requêtes de recherche sémantique sur l'index à l'aide de la recherche hybride ou de la recherche neuronale.

Prérequis

Pour utiliser la recherche sémantique, la version OpenSearch du cluster doit être 2.11 ou plus récente. Par défaut, les nouveaux clusters utilisent la version 2.11. Reportez-vous à Création d'un cluster OpenSearch.

Pour les clusters existants configurés pour la version 2.3, vous pouvez effectuer une mise à niveau en ligne vers la version 2.11. Pour plus d'informations, reportez-vous à OpenSearch Cluster Software Upgrades.

Pour mettre à niveau des clusters existants configurés pour la version 1.2.3 vers la version 2.11, vous devez utiliser le processus de mise à niveau décrit dans OpenSearch Cluster Software Upgrades.

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

Stratégie 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 OCI Search avec OpenSearch, vous n'avez pas besoin de configurer les droits d'accès, vous pouvez passer au prérequis suivant, Paramètres de cluster pour la recherche sémantique. Voir aussi Présentation de la recherche sémantique.

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

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

Si vous ne connaissez pas les stratégies, reportez-vous à Introduction aux stratégies et à Stratégies courantes.

Stratégie IAM pour les modèles personnalisés

Si vous utilisez un modèle personnalisé, vous devez accorder l'accès à OCI Search avec OpenSearch pour accéder au bucket Object Storage qui contient le modèle.

L'exemple de stratégie suivant inclut le droit d'accès requis :

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

Stratégie 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 à OCI Search avec OpenSearch pour accéder aux ressources d'IA générative.

L'exemple de stratégie suivant inclut le droit d'accès requis :

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 d'IA générative

Pour utiliser OCI Generative AI, votre location doit être abonnée à la région Midwest des Etats-Unis (Chicago) ou à la région Allemagne centrale (Francfort). Vous n'avez pas besoin de créer le cluster 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 cluster pour la recherche sémantique

Utilisez l'opération paramètres des API de cluster pour configurer les paramètres de cluster recommandés pour la recherche sémantique. L'exemple suivant inclut 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 de la configuration de la recherche neuronale consiste à configurer le grand modèle de langue que vous souhaitez utiliser. Le modèle est utilisé pour générer des incorporations vectorielles à partir de champs de texte.

Inscrire un groupe de modèles

Les groupes de modèles vous permettent de gérer l'accès à des modèles spécifiques. L'enregistrement d'un groupe de modèles est facultatif. Cependant, si vous n'enregistrez pas, 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 indiqué dans l'exemple suivant :

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

Notez le message model_group_id renvoyé dans la réponse :

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

Enregistrement du modèle dans le groupe de modèles

Inscrivez le modèle à l'aide de l'opération d'inscription à partir des API de modèle. Le contenu de la demande POST à 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 un cluster sans avoir à le télécharger, puis de le télécharger manuellement dans un bucket 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 avez uniquement besoin des éléments model_group_id, name, version et model_format du modèle. Pour savoir comment utiliser un modèle préentraîné, reportez-vous à Utilisation d'un modèle préentraîné OpenSearch.

  • Option 2 : Modèles personnalisés

    Vous devez transmettre l'URL Object Storage dans la section actions de l'opération d'inscription, par exemple :

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

    Pour obtenir un exemple complet d'opération de CdM, reportez-vous à la section Modèles personnalisés - 2 : Enregistrement du modèle.

  • Option 3 : connecteur Generative AI

    Vous pouvez également enregistrer et déployer un modèle d'intégration GenAI distant tel que cohere.embed-english-v3.0 dans votre cluster à 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 de connecteur, comme décrit dans les étapes suivantes.

    Remarque

    Si vous utilisez le modèle ON-DEMAND, restez à jour avec les notifications d'abandon de modèle du service GenAI et mettez à jour votre connecteur si nécessaire pour éviter d'éventuelles interruptions de service. Reportez-vous à Modèles de base préentraînés dans l'IA générative pour connaître 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 de l'exemple de charge utile suivant de ON-DEMAND à DEDICATED.

    Créer un connecteur pour le modèle d'intégration Cohere :

    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 une charge utile permettant de 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"
             }
         ]
     }

Une fois la demande d'inscription effectuée, vous pouvez vérifier le statut de l'opération, utiliser task_id avec l'opération Get des API des tâches, comme indiqué dans l'exemple suivant :

GET /_plugins/_ml/tasks/<task_ID>

Une fois l'opération d'inscription terminée, la valeur status dans la réponse à l'opération Get est COMPLETED, comme indiqué 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 renvoyée dans la réponse à utiliser lors du déploiement du modèle.

Déploiement du modèle

Une fois l'opération d'inscription terminée pour le modèle, vous pouvez déployer le modèle vers le cluster à 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 indiqué dans l'exemple suivant :

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

Notez la valeur task_id renvoyé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'inscription, utilisez task_id avec l'opération Get des API des tâches, comme indiqué 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.

Assimilation des données

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

Inclure les données dans l'index

Après avoir créé un index, vous pouvez désormais l'inclure dans l'index, comme indiqué 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 correctement ingérés et que les incorporations sont générées automatiquement lors de l'ingestion :
GET /test-index/_doc/3

Créer un pipeline d'inclusion

A l'aide de l'ID de modèle du modèle déployé, créez un pipeline d'inclusion comme indiqué 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'inclusion 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 inclure les données, le pipeline trouve automatiquement le champ "passage_text", et utilise le modèle de pipeline pour générer les incorporations correspondantes, "passage_embedding", puis les met en correspondance avant l'indexation.

N'oubliez pas que "passage_text" → "passage_embedding" sont définis par l'utilisateur et peuvent être tout ce que vous voulez. Veillez à la cohérence de la dénomination lors de la création de l'index dans lequel 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 indiquer le pipeline à utiliser pour l'inclusion de 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, reportez-vous à 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
}

Inclure les données dans l'index

Après avoir créé un index, vous pouvez désormais l'inclure dans l'index, comme indiqué 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 correctement ingérés et que les incorporations sont générées automatiquement lors de l'ingestion :

GET /test-index/_doc/3