Partager via


Créer un index vectoriel

Dans Recherche Azure AI, vous pouvez utiliser l’API REST (Create or Update Index) pour stocker des vecteurs dans un index de recherche. Un index vectoriel est défini par un schéma d’index qui a des champs vectoriels, des champs non vecteurs et une section de configuration vectorielle.

Lorsque vous créez un index vectoriel, vous créez implicitement un espace d’incorporation qui sert de corpus pour les requêtes vectorielles. L’espace d’incorporation se compose de tous les champs vectoriels remplis avec des incorporations à partir du même modèle d’incorporation. Au moment de la requête, le système compare la requête vectorielle aux vecteurs indexés, retournant les résultats en fonction de la similarité sémantique.

Pour indexer des vecteurs dans Recherche IA Azure, procédez comme suit :

  • Commencez par une définition de schéma de base.
  • Ajoutez des algorithmes vectoriels et une compression facultative.
  • Ajoutez des définitions de champ vectoriel.
  • Chargez des données prévectorisées en tant qu’étape distincte ou utilisez la vectorisation intégrée pour la segmentation des données et l’incorporation pendant l’indexation.

Cet article utilise REST pour l’illustration. Après avoir compris le flux de travail de base, poursuivez avec les exemples de code du Kit de développement logiciel (SDK) Azure dans le référentiel azure-search-vector-samples , qui fournit des conseils sur l’utilisation de vecteurs dans le code de test et de production.

Conseil

Vous pouvez également utiliser le portail Azure pour créer un index vectoriel et essayer la segmentation et la vectorisation des données intégrées.

Prérequis

  • Un service Recherche d’IA Azure dans n’importe quelle région et sur n’importe quel niveau. Si vous envisagez d’utiliser la vectorisation intégrée avec les compétences et les vectoriseurs Azure AI, Azure AI Search doit se trouver dans la même région que les modèles d’incorporation hébergés sur Azure AI Vision.

  • Vos documents sources doivent avoir des incorporations vectorielles à charger dans l’index. Vous pouvez également utiliser la vectorisation intégrée pour cette étape.

  • Vous devez connaître la limite des dimensions du modèle qui crée les incorporations afin de pouvoir affecter cette limite au champ vectoriel. Pour text-embedding-ada-002, les dimensions sont fixées à 1 536. Pour text-embedding-3-small ou text-embedding-3-large, les dimensions varient de 1 à 1536 et de 1 à 3072, respectivement.

  • Vous devez connaître la métrique de similarité à utiliser. Pour l’incorporation de modèles sur Azure OpenAI, la similarité est calculée à l’aide cosinede .

  • Vous devez savoir comment créer un index. Un schéma inclut toujours un champ pour la clé de document, les champs pour la recherche ou les filtres, ainsi que d’autres configurations pour les comportements nécessaires lors de l’indexation et des requêtes.

Limites

Certains services de recherche créés avant janvier 2019 ne peuvent pas créer d’index vectoriel. Si cela vous concerne, créez un nouveau service pour utiliser des vecteurs.

Préparer des documents pour l’indexation

Avant l’indexation, assemblez une charge utile de document qui inclut des champs de données vectorielles et non vectorielles. La structure du document doit être conforme à la collection de champs de schéma d’index.

Vérifiez que vos documents sources fournissent le contenu suivant :

Contenu Descriptif
Identificateur unique Champ ou propriété de métadonnées qui identifie de manière unique chaque document. Tous les index de recherche nécessitent une clé de document. Pour répondre aux exigences de clé de document, un document source doit avoir un champ ou une propriété qui l’identifie de manière unique dans l’index. Si vous indexez des objets blob, il peut s’agir de la metadata_storage_path qui identifie de manière unique chaque objet blob. Si vous indexez à partir d’une base de données, il peut s’agir de la clé primaire. Ce champ source doit être mappé à un champ d’index de type Edm.String et key=true dans l’index de recherche.
Contenu non vectoriel Fournissez d’autres champs avec du contenu lisible par l’homme. Le contenu lisible par l’homme est utile pour la réponse aux requêtes et pour les requêtes hybrides qui incluent la recherche en texte intégral ou le classement sémantique dans la même requête. Si vous utilisez un modèle d’achèvement de conversation, la plupart des modèles comme ChatGPT attendent du texte lisible par l’homme et n’acceptent pas de vecteurs bruts comme entrée.
Contenu vectoriel Représentation vectorisée de votre contenu non vecteur à utiliser au moment de la requête. Un vecteur est un tableau de nombres à virgule flottante à simple précision générés par un modèle d'embedding. Chaque champ vectoriel contient un tableau généré par un modèle. Il existe une incorporation par champ, où le champ est un champ de niveau supérieur (qui ne fait pas partie d’un type imbriqué ou complexe). Pour une intégration simple, nous vous recommandons d’incorporer des modèles dans Azure OpenAI, tels que l’incorporation de texte 3 pour les documents texte ou l’API REST Récupération d’images pour les images et les incorporations modales.

Si vous pouvez utiliser des indexeurs et des ensembles de compétences, envisagez la vectorisation intégrée, qui encode des images et du texte pendant l’indexation. Vos définitions de champ sont destinées aux champs vectoriels, mais les données sources entrantes peuvent être du texte ou des images convertis en tableaux de vecteurs lors de l’indexation.

Votre index de recherche doit inclure des champs et du contenu pour tous les scénarios de requête que vous souhaitez prendre en charge. Supposons que vous souhaitez rechercher ou filtrer les noms de produits, les versions, les métadonnées ou les adresses. Dans ce cas, la recherche de similarité vectorielle n’est pas particulièrement utile. La recherche de mots clés, la recherche géographique ou les filtres qui itèrent sur le contenu détaillé seraient un meilleur choix. Un index de recherche inclus dans les champs vectoriels et non vecteurs offre une flexibilité maximale pour la construction des requêtes et la composition de la réponse.

Pour obtenir un court exemple de charge utile de documents qui inclut des champs vectoriels et non vecteurs, consultez la section données du vecteur de charge de cet article.

Commencer avec un index de base

Commencez par un schéma minimal pour que vous ayez une définition à utiliser avant d’ajouter une configuration vectorielle et des champs vectoriels. Un index simple peut ressembler à l’exemple suivant. Pour plus d’informations sur un schéma d’index, consultez Créer un index de recherche.

Notez que l’index a un nom obligatoire, une clé de document requise ("key": true) et des champs pour le contenu lisible par l’homme en texte brut. Il est courant d’avoir une version lisible par l’homme de tout contenu que vous envisagez de vectoriser. Par exemple, si vous avez un bloc de texte à partir d’un fichier PDF, votre schéma d’index doit avoir un champ pour les blocs de texte brut et un deuxième champ pour les blocs vectorisés.

Voici un index de base avec un "name", une collection "fields", et d’autres constructions pour une configuration supplémentaire :

POST https://[servicename].search.windows.net/indexes?api-version=[api-version] 
{
  "name": "example-index",
  "fields": [
    { "name": "documentId", "type": "Edm.String", "key": true, "retrievable": true, "searchable": true, "filterable": true },
    { "name": "myHumanReadableNameField", "type": "Edm.String", "retrievable": true, "searchable": true, "filterable": false, "sortable": true, "facetable": false },
    { "name": "myHumanReadableContentField", "type": "Edm.String", "retrievable": true, "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.microsoft" },
  ],
  "analyzers": [ ],
  "scoringProfiles": [ ],
  "suggesters": [ ],
  "vectorSearch": [ ]
}

Ajouter une configuration de recherche vectorielle

Ensuite, ajoutez une "vectorSearch" configuration à votre schéma. Il est utile de spécifier une configuration avant les définitions de champs, car les profils que vous définissez ici font partie de la définition du champ vecteur. Dans le schéma, la configuration vectorielle est généralement insérée après la collection de champs, peut-être après "analyzers", "scoringProfiles"et "suggesters". Toutefois, l’ordre n’a pas d’importance.

Une configuration vectorielle inclut :

  • vectorSearch.algorithms utilisé lors de l’indexation pour créer des informations « voisin le plus proche » entre les nœuds vectoriels.
  • vectorSearch.compressions pour la quantisation scalaire ou binaire, l’échantillonnage et le reclassement avec des vecteurs d’origine.
  • vectorSearch.profiles pour spécifier plusieurs combinaisons d’algorithmes et de configurations de compression.

2024-07-01 est en disponibilité générale. Il prend en charge une configuration vectorielle qui a :

  • Algorithme HNSW (Hierarchical Navigable Small World).
  • Algorithme exhaustif des k-plus-proches voisins (KNN).
  • Compression scalaire.
  • Compression binaire, disponible en 2024-07-01 uniquement et dans les packages de SDK Azure plus récents.
  • Suréchantillonnage.
  • Reclassement avec des vecteurs d’origine.

Si vous choisissez HNSW pour un champ, vous pouvez opter pour un KNN exhaustif au moment de la requête. Toutefois, le contraire ne fonctionne pas. Si vous choisissez exhaustive pour l’indexation, vous ne pouvez pas demander ultérieurement la recherche HNSW, car les structures de données supplémentaires qui activent la recherche approximative n’existent pas.

Veillez à avoir une stratégie pour vectoriser votre contenu. Nous vous recommandons la vectorisation intégrée et les vectoriseurs au moment de la requête pour l’encodage intégré.

  1. Utilisez l’API REST Créer ou mettre à jour l’index pour créer l’index.

  2. Ajoutez une section vectorSearch dans l’index qui spécifie les algorithmes de recherche utilisés pour créer l’espace d’incorporation.

     "vectorSearch": {
         "compressions": [
             {
                 "name": "scalar-quantization",
                 "kind": "scalarQuantization",
                 "rerankWithOriginalVectors": true,
                 "defaultOversampling": 10.0,
                     "scalarQuantizationParameters": {
                         "quantizedDataType": "int8"
                     }
             },
             {
                 "name": "binary-quantization",
                 "kind": "binaryQuantization",
                 "rerankWithOriginalVectors": true,
                 "defaultOversampling": 10.0
             }
         ],
         "algorithms": [
             {
                 "name": "hnsw-1",
                 "kind": "hnsw",
                 "hnswParameters": {
                     "m": 4,
                     "efConstruction": 400,
                     "efSearch": 500,
                     "metric": "cosine"
                 }
             },
             {
                 "name": "hnsw-2",
                 "kind": "hnsw",
                 "hnswParameters": {
                     "m": 8,
                     "efConstruction": 800,
                     "efSearch": 800,
                     "metric": "hamming"
                 }
             },
             {
                 "name": "eknn",
                 "kind": "exhaustiveKnn",
                 "exhaustiveKnnParameters": {
                     "metric": "euclidean"
                 }
             }
    
         ],
         "profiles": [
           {
             "name": "vector-profile-hnsw-scalar",
             "compression": "scalar-quantization",
             "algorithm": "hnsw-1"
           }
         ]
     }
    

    Points essentiels :

    • Les noms de chaque configuration de compression, d’algorithme et de profil doivent être uniques pour son type dans l’index.

    • vectorSearch.compressions peut avoir la valeur scalarQuantization ou binaryQuantization. La quantification scalaire compresse les valeurs flottantes en types de données plus étroits. La quantisation binaire convertit les floats en valeurs binaires 1 bits.

    • vectorSearch.compressions.rerankWithOriginalVectors utilise les vecteurs originaux non compressés pour recalculer la similarité et reclasser les meilleurs résultats renvoyés par la requête de recherche initiale. Les vecteurs non compressés existent dans l'index de recherche même si stored sont faux. Cette propriété est facultative. La valeur par défaut est true.

    • vectorSearch.compressions.defaultOversampling considère un ensemble plus large de résultats potentiels pour compenser la réduction des informations résultant de la quantification. La formule des résultats potentiels consiste en le k dans la requête, avec un multiplicateur de suréchantillonnage. Par exemple, si la requête spécifie une k valeur de 5 et que l’échantillonnage est supérieur à 20, la requête demande efficacement 100 documents à utiliser dans le reclassement, à l’aide du vecteur non compressé d’origine à cet effet. Seuls les résultats k les mieux classés sont renvoyés. Cette propriété est facultative. La valeur par défaut est 4.

    • vectorSearch.compressions.scalarQuantizationParameters.quantizedDataType doit être défini sur int8. Il s’agit du seul type de données primitif pris en charge pour le moment. Cette propriété est facultative. La valeur par défaut est int8.

    • vectorSearch.algorithms est hnsw ou exhaustiveKnn. Il s’agit des algorithmes des plus proches voisins approximatifs (ANN) utilisés pour organiser le contenu vectoriel pendant l’indexation.

    • vectorSearch.algorithms.m est le nombre de liens bidirectionnels. La valeur par défaut est 4. La fourchette est comprise entre 4 et 10. Des valeurs inférieures devraient produire moins de bruit dans les résultats.

    • vectorSearch.algorithms.efConstruction est le nombre de plus proches voisins utilisés lors de l’indexation. La valeur par défaut est 400. La plage est comprise entre 100 et 1,000.

    • "vectorSearch.algorithms.efSearch est le nombre de plus proches voisins utilisés lors de la recherche. La valeur par défaut est 500. La plage est comprise entre 100 et 1,000.

    • vectorSearch.algorithms.metric doit être cosine si vous utilisez Azure OpenAI, sinon utilisez la métrique de similarité associée au modèle d’incorporation que vous utilisez. Les valeurs prises en charge sont cosine, dotProductet euclideanhamming (utilisées pour l’indexation des données binaires).

    • vectorSearch.profiles ajouter une couche d’abstraction pour accueillir des définitions plus riches. Un profil est défini dans vectorSearch et référencé par son nom dans chaque champ vectoriel. Il s’agit d’une combinaison de configurations de compression et d’algorithme. Vous affectez cette propriété à un champ vectoriel et détermine l’algorithme et la compression des champs.

Ajouter un champ vectoriel à la collection de champs

Une fois que vous avez une configuration vectorielle, vous pouvez ajouter un champ vectoriel à la collection de champs. Rappelez-vous que la collection de champs doit inclure un champ pour la clé de document, les champs vectoriels et tous les autres champs non vecteurs dont vous avez besoin pour les scénarios de recherche hybride ou la saisie semi-automatique du modèle de conversation dans les charges de travail RAG.

Les champs vectoriels sont caractérisés par leur type de données, une dimensions propriété basée sur le modèle d’incorporation utilisé pour générer les vecteurs et un profil vectoriel que vous avez créé à l’étape précédente.

2024-07-01 est en disponibilité générale.

  1. Utilisez l’API REST Créer ou mettre à jour l’index pour créer l’index et ajouter un champ vectoriel à la collection de champs.

    {
      "name": "example-index",
      "fields": [
        {
            "name": "contentVector",
            "type": "Collection(Edm.Single)",
            "searchable": true,
            "retrievable": false,
            "stored": false,
            "dimensions": 1536,
            "vectorSearchProfile": "vector-profile-1"
        }
      ]
    }
    
  2. Spécifiez un champ vectoriel avec les attributs suivants. Vous pouvez stocker un incorporation généré par champ. Pour chaque champ vectoriel :

    • type doit être un type de données vectorielle. Collection(Edm.Single) est le plus courant pour les modèles d’incorporation.
    • dimensions correspond au nombre de dimensions générées par le modèle d'intégration. Pour text-embedding-ada-002, la valeur est fixée à 1536. Pour la série de modèles text-embedding-3, il existe une plage de valeurs. Si vous utilisez la vectorisation intégrée et une compétence d’incorporation pour générer des vecteurs, vérifiez que cette propriété a la même valeur de dimensions que celle utilisée par la compétence d’incorporation.
    • vectorSearchProfile est le nom d’un profil défini ailleurs dans l’index.
    • searchable doit être true.
    • retrievable peut avoir la valeur « true » ou « false ». True retourne les vecteurs bruts (1 536 d’entre eux) en texte brut et consomme de l’espace de stockage. Définissez la valeur true si vous transmettez un résultat vectoriel à une application en aval.
    • stored peut avoir la valeur « true » ou « false ». Il détermine si une copie supplémentaire de vecteurs est stockée pour la récupération. Pour plus d’informations, consultez Réduire la taille des vecteurs.
    • filterable, facetableet sortable doit être faux.
  3. Ajoutez des champs non vectoriels filtrables à la collection, par title exemple avec filterable la valeur true, si vous souhaitez appeler le préfiltrage ou le postfiltrage sur la requête vectorielle.

  4. Ajoutez d’autres champs qui définissent la substance et la structure du contenu textuel que vous indexez. Au minimum, vous avez besoin d'une clé de document.

    Vous devez également ajouter des champs utiles à la requête ou à la réponse. L’exemple suivant montre des champs vectoriels pour le titre et le contenu (titleVector et contentVector) équivalents aux vecteurs. Il fournit également des champs pour le contenu textuel équivalent (title et content) qui sont utiles pour le tri, le filtrage et la lecture dans un résultat de recherche.

    L'exemple suivant montre la collection de champs :

    PUT https://my-search-service.search.windows.net/indexes/my-index?api-version=2024-07-01&allowIndexDowntime=true
    Content-Type: application/json
    api-key: {{admin-api-key}}
    {
        "name": "{{index-name}}",
        "fields": [
            {
                "name": "id",
                "type": "Edm.String",
                "key": true,
                "filterable": true
            },
            {
                "name": "title",
                "type": "Edm.String",
                "searchable": true,
                "filterable": true,
                "sortable": true,
                "retrievable": true
            },
            {
                "name": "titleVector",
                "type": "Collection(Edm.Single)",
                "searchable": true,
                "retrievable": true,
                "stored": true,
                "dimensions": 1536,
                "vectorSearchProfile": "vector-profile-1"
            },
            {
                "name": "content",
                "type": "Edm.String",
                "searchable": true,
                "retrievable": true
            },
            {
                "name": "contentVector",
                "type": "Collection(Edm.Single)",
                "searchable": true,
                "retrievable": false,
                "stored": false,
                "dimensions": 1536,
                "vectorSearchProfile": "vector-profile-1"
            }
        ],
        "vectorSearch": {
            "algorithms": [
                {
                    "name": "hnsw-1",
                    "kind": "hnsw",
                    "hnswParameters": {
                        "m": 4,
                        "efConstruction": 400,
                        "efSearch": 500,
                        "metric": "cosine"
                    }
                }
            ],
            "profiles": [
                {
                    "name": "vector-profile-1",
                    "algorithm": "hnsw-1"
                }
            ]
        }
    }
    

Charger des données vectorielles pour l’indexation

Le contenu que vous fournissez pour l'indexation doit être conforme au schéma de l'index et inclure une chaîne de valeur unique pour la clé du document. Les données prévectorisées sont chargées dans un ou plusieurs champs vectoriels, qui peuvent coexister avec d’autres champs contenant du contenu non vectoriel.

Pour l’ingestion des données, vous pouvez utiliser des méthodologies Push ou Pull.

Utilisez Documents – Index pour charger des données vectorielles et non vectorielles dans un index. Les API d’envoi (push) pour l’indexation sont identiques dans toutes les versions stables et préliminaires. Utilisez l’une des API suivantes pour charger des documents :

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/index?api-version=2024-07-01

{
    "value": [
        {
            "id": "1",
            "title": "Azure App Service",
            "content": "Azure App Service is a fully managed platform for building, deploying, and scaling web apps. You can host web apps, mobile app backends, and RESTful APIs. It supports a variety of programming languages and frameworks, such as .NET, Java, Node.js, Python, and PHP. The service offers built-in auto-scaling and load balancing capabilities. It also provides integration with other Azure services, such as Azure DevOps, GitHub, and Bitbucket.",
            "category": "Web",
            "titleVector": [
                -0.02250031754374504,
                 . . . 
                        ],
            "contentVector": [
                -0.024740582332015038,
                 . . .
            ],
            "@search.action": "upload"
        },
        {
            "id": "2",
            "title": "Azure Functions",
            "content": "Azure Functions is a serverless compute service that enables you to run code on-demand without having to manage infrastructure. It allows you to build and deploy event-driven applications that automatically scale with your workload. Functions support various languages, including C#, F#, Node.js, Python, and Java. It offers a variety of triggers and bindings to integrate with other Azure services and external services. You only pay for the compute time you consume.",
            "category": "Compute",
            "titleVector": [
                -0.020159931853413582,
                . . .
            ],
            "contentVector": [
                -0.02780858241021633,
                 . . .
            ],
            "@search.action": "upload"
        }
        . . .
    ]
}

Interroger votre index pour le contenu vectoriel

À des fins de validation, vous pouvez interroger l’index à l’aide de l’Explorateur de recherche sur le Portail Azure ou d’un appel d’API REST. Étant donné qu’Azure AI Search ne peut pas convertir un vecteur en texte lisible par l’homme, essayez de renvoyer des champs du même document qui fournissent des preuves de la correspondance. Par exemple, si la requête vectorielle cible le titleVector champ, vous pouvez sélectionner title les résultats de la recherche.

Les champs doivent être marqués retrievable pour être inclus dans les résultats.

  • Passez en revue les index dans Gestion de la recherche>Index pour afficher toutes les tailles d’index et la taille de l’index vectoriel. Une taille d’index vectoriel positif indique que des vecteurs sont présents.

  • Utilisez l’Explorateur de recherche pour interroger un index. L’Explorateur de recherche a deux vues : la vue Requête (par défaut) et la vue JSON.

    • Définissez Options de requête>Masquer les valeurs de vecteur dans les résultats de la recherche pour obtenir des résultats plus lisibles.

    • Utilisez la vue JSON pour les requêtes vectorielles. Vous pouvez coller une définition JSON de la requête vectorielle que vous souhaitez exécuter. Si votre index a une affectation de vectoriseur, vous pouvez également utiliser la conversion de texte en vecteur ou d’image en vecteur intégrée. Pour plus d’informations sur la recherche d’images, consultez Démarrage rapide : Rechercher des images dans l’Explorateur de recherche.

    • Utilisez la vue Requête par défaut pour une confirmation rapide que l’index contient des vecteurs. L’affichage de requête est destiné à la recherche en texte intégral. Bien que vous ne puissiez pas l’utiliser pour les requêtes vectorielles, vous pouvez envoyer une recherche vide (search=*) pour rechercher du contenu. Le contenu de tous les champs, y compris les champs vectoriels, est retourné sous forme de texte brut.

Pour plus d’informations, consultez Créer une requête vectorielle.

Mettre à jour un index vectoriel

Pour mettre à jour un index vectoriel, modifiez le schéma et rechargez les documents pour remplir de nouveaux champs. Les API pour les mises à jour de schéma incluent Create or Update Index (REST), CreateOrUpdateIndex dans le SDK Azure pour .NET, create_or_update_index dans le SDK Azure pour Python et des méthodes similaires dans d’autres SDK Azure.

Pour obtenir des instructions standard sur la mise à jour d’un index, consultez Mettre à jour ou reconstruire un index.

Les points clés sont les suivants :

  • La suppression et la reconstruction complète de l'index sont souvent nécessaires pour mettre à jour et supprimer des champs existants.

  • Vous pouvez apporter les modifications suivantes sans condition de reconstruction :

    • Ajouter de nouveaux champs à une collection de champs.
    • Ajoutez de nouvelles configurations vectorielles, affectées à de nouveaux champs, mais pas des champs existants déjà vectorisés.
    • Modifiez retrievable (les valeurs sont vraies ou false) sur un champ existant. Les champs vectoriels doivent pouvoir faire l’objet d’une recherche et être récupérables. Toutefois, si vous souhaitez désactiver l’accès à un champ vectoriel dans des situations où la suppression et la régénération ne sont pas réalisables, vous pouvez définir retrievable sur false.

Étapes suivantes

À l’étape suivante, nous vous recommandons de créer une requête vectorielle.

Les exemples de code du référentiel azure-search-vector-samples illustrent des workflows de bout en bout qui incluent la définition de schéma, la vectorisation, l’indexation et les requêtes.

Le code de démonstration est disponible en Python, C# et JavaScript.