Definición de una proyección de índice para la indexación de elementos primarios y secundarios
Para los índices que contienen documentos fragmentados, una proyección de índice especifica cómo se asigna el contenido primario y secundario a los campos de un índice de búsqueda para la indexación de uno a varios. A través de una proyección de índice, puede enviar contenido a:
Un índice único, donde los campos primarios se repiten para cada fragmento, pero el intervalo de agregación del índice está a nivel de fragmento. El tutorial RAG es un ejemplo de este enfoque.
Dos o más índices, donde el índice primario tiene campos relacionados con el documento primario y el índice secundario se organiza en torno a fragmentos. El índice secundario es el corpus de búsqueda principal, pero el índice primario podría usarse para consultas de búsqueda cuando quiera recuperar los campos primarios de un fragmento determinado o para consultas independientes.
La mayoría de las implementaciones son un índice único organizado en torno a fragmentos con campos primarios, como el nombre de archivo del documento, que se repiten para cada fragmento. Sin embargo, el sistema está diseñado para admitir índices secundarios e independientes si ese es su requisito. Búsqueda de Azure AI no admite combinaciones de índice, por lo que el código de la aplicación debe controlar el índice que se va a usar.
Una proyección de índice se define en un conjunto de aptitudes. Es responsable de coordinar el proceso de indexación que envía fragmentos de contenido a un índice de búsqueda, junto con el contenido primario asociado a cada fragmento. Mejora el funcionamiento de la fragmentación de datos nativos al proporcionar más opciones para controlar cómo se indexa el contenido primario y secundario.
En este artículo se explica cómo crear el esquema de índice y los patrones de proyección del indexador para la indexación de uno a varios.
Requisitos previos
Un índice (uno o varios) que acepta la salida de la canalización del indexador.
Un origen de datos compatible con el contenido que desea fragmentar. Puede ser contenido vectorial o no vectorial.
Una aptitud que divide el contenido en fragmentos, ya sea la aptitud Dividir texto o una aptitud personalizada que proporcione una funcionalidad equivalente.
El conjunto de aptitudes contiene la proyección del indexador que da forma a los datos para la indexación de uno a varios. Un conjunto de aptitudes también podría tener otras aptitudes, como una aptitud de inserción como AzureOpenAIEmbedding si el escenario incluye vectorización integrada.
Dependencia del procesamiento del indexador
La indexación de uno a varios toma una dependencia de los conjuntos de aptitudes y la indexación basada en indexadores que incluye los siguientes cuatro componentes:
- Un origen de datos
- Uno o varios índices para el contenido que se puede buscar
- Conjunto de aptitudes que contiene una proyección de índice*
- Un indexador
Los datos se pueden originar en cualquier origen de datos compatible, pero la suposición es que el contenido es lo suficientemente grande como para fragmentarlo y el motivo de la fragmentación es que está implementando un patrón RAG que proporciona datos de base a un modelo de chat. O bien, está implementando el vector de búsqueda y necesita cumplir los requisitos de tamaño de entrada más pequeños de los modelos de inserción.
Los indexadores cargan datos indexados en un índice predefinido. La forma de definir el esquema y si usar uno o varios índices es la primera decisión que se debe tomar en un escenario de indexación de uno a varios. En la siguiente sección se describe el diseño del índice.
Creación de un índice para la indexación de uno a varios
Tanto si se crea un índice para los fragmentos que repiten valores primarios, como índices independientes para la colocación de campos primarios y secundarios, el índice principal usado para la búsqueda se diseña en torno a los fragmentos de datos. Debe tener los siguientes campos:
Un campo de clave del documento que identifica de forma única cada documento. Debe definirse como tipo
Edm.String
con el analizadorkeyword
.Un campo que asocia cada fragmento con su elemento primario. Debe ser del tipo
Edm.String
. No puede ser el campo de clave del documento y debe tenerfilterable
establecido en true. Se conoce como parent_id en los ejemplos y como un valor de clave proyectado en este artículo.Otros campos para el contenido, como los campos de texto o de fragmentos vectorizados.
Debe existir un índice en el servicio de búsqueda antes de crear el conjunto de aptitudes o ejecutar el indexador.
Esquema de índice único inclusivo de campos primarios y secundarios
Un único índice diseñado en torno a fragmentos con contenido primario que se repite para cada fragmento es el patrón predominante para escenarios de vector de búsqueda y RAG. La capacidad de asociar el contenido primario correcto a cada fragmento se habilita a través de proyecciones de índice.
El siguiente esquema es un ejemplo que cumple los requisitos de las proyecciones de índice. En este ejemplo, los campos primarios son el parent_id y el título. Los campos secundarios son los fragmentos vectoriales y no vectoriales. El chunk_id es el identificador de documento de este índice. El parent_id y el título se repiten para cada fragmento del índice.
Puede usar Azure Portal, las API de REST o un SDK de Azure para crear un índice.
{
"name": "my_consolidated_index",
"fields": [
{"name": "chunk_id", "type": "Edm.String", "key": true, "filterable": true, "analyzer": "keyword"},
{"name": "parent_id", "type": "Edm.String", "filterable": true},
{"name": "title", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "retrievable": true},
{"name": "chunk", "type": "Edm.String","searchable": true,"retrievable": true},
{"name": "chunk_vector", "type": "Collection(Edm.Single)", "searchable": true, "retrievable": false, "stored": false, "dimensions": 1536, "vectorSearchProfile": "hnsw"}
],
"vectorSearch": {
"algorithms": [{"name": "hsnw", "kind": "hnsw", "hnswParameters": {}}],
"profiles": [{"name": "hsnw", "algorithm": "hnsw"}]
}
}
Adición de proyecciones de índice a un conjunto de aptitudes
Las proyecciones de índice se definen dentro de una definición de conjunto de aptitudes y se definen principalmente como una matriz de selectors
, donde cada selector corresponde a un índice de destino diferente en el servicio de búsqueda. Esta sección comienza con la sintaxis y los ejemplos del contexto, seguido de la referencia de parámetros.
Elija una pestaña para la sintaxis de la API. Actualmente no hay compatibilidad con el portal para configurar proyecciones, aparte de editar la definición JSON del conjunto de aptitudes. Consulte el ejemplo de REST para JSON.
Las proyecciones de índice están disponibles con carácter general. Recomendamos la API estable más reciente:
Esta es una carga de ejemplo para una definición de proyecciones de índices que puede usar para proyectar la salida de páginas individuales mediante la aptitud Dividir texto como sus propios documentos en el índice de búsqueda.
"indexProjections": {
"selectors": [
{
"targetIndexName": "my_consolidated_index",
"parentKeyFieldName": "parent_id",
"sourceContext": "/document/pages/*",
"mappings": [
{
"name": "chunk",
"source": "/document/pages/*",
"sourceContext": null,
"inputs": []
},
{
"name": "chunk_vector",
"source": "/document/pages/*/chunk_vector",
"sourceContext": null,
"inputs": []
},
{
"name": "title",
"source": "/document/title",
"sourceContext": null,
"inputs": []
}
]
}
],
"parameters": {
"projectionMode": "skipIndexingParentDocuments"
}
}
Referencia de los parámetros
Parámetros de proyección de índice | Definición |
---|---|
selectors |
Parámetros para el corpus de búsqueda principal, normalmente el diseñado en torno a los fragmentos. |
projectionMode |
Parámetro opcional que proporciona instrucciones al indexador. El único valor válido para este parámetro es skipIndexingParentDocuments y se usa cuando el índice de fragmento es el corpus de búsqueda principal y debe especificar si los campos primarios se indexan como documentos de búsqueda adicionales dentro del índice fragmentado. Si no establece skipIndexingParentDocuments , obtendrá documentos de búsqueda adicionales en el índice que son NULL para los fragmentos, pero rellenados solo con campos primarios. Por ejemplo, si cinco documentos contribuyen con 100 fragmentos al índice, el número de documentos del índice es 105. Los cinco documentos creados o campos primarios tienen valores NULL para los campos de fragmento (secundario), por lo que son sustancialmente diferentes de la mayor parte de los documentos del índice. Se recomienda establecer projectionMode en skipIndexingParentDocument . |
Los selectores tienen los siguientes parámetros como parte de su definición.
Parámetros del selector | Definición |
---|---|
targetIndexName |
El nombre del índice en el que se proyectan los datos de índice. O bien es el único índice fragmentado con campos primarios repetidos, o bien es el índice secundario si está usando índices independientes para el contenido primario y secundario. |
parentKeyFieldName |
El nombre del campo que proporciona la clave para el documento primario. |
sourceContext |
La anotación de enriquecimiento que define la granularidad con la que se asignan los datos a documentos de búsqueda individuales. Para obtener más información, consulte Contexto de aptitud y lenguaje de anotación de entradas. |
mappings |
Una matriz de asignaciones de datos enriquecidos a campos del índice de búsqueda. Cada asignación consta de lo siguiente: name : nombre del campo en el índice de búsqueda en el que se deben indexar los datos. source : ruta de acceso de la anotación de enriquecimiento de la que se deben extraer los datos. Cada elemento mapping también puede definir datos de forma recursiva con un campo opcional sourceContext y inputs , similar al almacén de conocimiento o la aptitud Conformador. En función de la aplicación, estos parámetros permiten dar forma a los datos en campos de tipo Edm.ComplexType en el índice de búsqueda. Algunos LLM no aceptan un tipo complejo en los resultados de búsqueda, por lo que el LLM que está usando determina si una asignación de tipo complejo es útil o no. |
El parámetro mappings
es importante. Debe asignar explícitamente todos los campos del índice secundario, excepto los campos de identificador, como la clave de documento y el identificador primario.
Este requisito contrasta con otras convenciones de asignación de campos en Búsqueda de Azure AI. Para algunos tipos de origen de datos, el indexador puede asignar implícitamente campos basados en nombres similares o características conocidas (por ejemplo, los indexadores de blobs usan la ruta de acceso de almacenamiento de metadatos única como clave de documento predeterminada). Sin embargo, para las proyecciones del indexador, debe especificar explícitamente todas las asignaciones de campos en el lado "varios" de la relación.
No cree una asignación de campos para el campo de clave principal. Si lo hace, interrumpirá el seguimiento de cambios y la actualización de datos sincronizada.
Control de documentos primarios
Ahora que ha visto varios patrones para indexaciones de uno a varios, vamos a comparar las diferencias clave sobre cada opción. Las proyecciones de índice generan efectivamente documentos "secundarios" para cada documento "primario" que se ejecuta a través de un conjunto de aptitudes. Tiene varias opciones para controlar los documentos "primarios".
Para enviar documentos primarios y secundarios a índices independientes, establezca el
targetIndexName
para la definición del indexador en el índice primario y establezca eltargetIndexName
en el selector de proyección de índice en el índice secundario.Para mantener los documentos primarios y secundarios en el mismo índice, establezca el
targetIndexName
del indexador y la proyección de índicetargetIndexName
en el mismo índice.Para evitar crear documentos de búsqueda primarios y asegurarse de que el índice contiene solo documentos secundarios de un intervalo de agregación uniforme, establezca el
targetIndexName
para la definición del indexador y el selector en el mismo índice, pero agregue un objetoparameters
adicional después deselectors
, con una claveprojectionMode
establecida enskipIndexingParentDocuments
, como se muestra aquí:"indexProjections": { "selectors": [ ... ], "parameters": { "projectionMode": "skipIndexingParentDocuments" } }
Revisión de asignaciones de campos
Los indexadores están afiliados a tres tipos diferentes de asignaciones de campos. Antes de ejecutar el indexador, compruebe las asignaciones de campos y sepa cuándo usar cada tipo.
Las asignaciones de campos se definen en un indexador y se usan para asignar un campo de origen a un campo de índice. Las asignaciones de campos se usan para rutas de datos que toman los datos del origen y los pasan para la indexación, sin ningún paso intermedio de procesamiento de aptitudes. Normalmente, un indexador puede asignar automáticamente campos con el mismo nombre y tipo. Las asignaciones de campos explícitas solo son necesarias cuando hay discrepancias. En la indexación de uno a varios y los patrones descritos hasta ahora, es posible que no necesite asignaciones de campos.
Las asignaciones de campos de salida se definen en un indexador y se usan para asignar contenido enriquecido generado por un conjunto de aptitudes a un campo en el índice principal. En los patrones de uno a varios descritos en este artículo, este es el índice primario de una solución de dos índices. En los ejemplos que se muestran en este artículo, el índice primario es escaso, con solo un campo de título, y ese campo no se rellena con contenido del procesamiento del conjunto de aptitudes, por lo que no tenemos una asignación de campo de salida.
Las asignaciones de campos de proyección del indexador se usan para asignar contenido generado por conjuntos de aptitudes a los campos del índice secundario. En los casos en los que el índice secundario también incluye campos primarios (como en la solución de índice consolidado), debe configurar asignaciones de campos para cada campo que tenga contenido, incluido el campo de título de nivel primario, suponiendo que desee que el título se muestre en cada documento fragmentado. Si usa índices primarios y secundarios independientes, las proyecciones del indexador deben tener asignaciones de campos solo para los campos de nivel secundario.
Nota:
Tanto las asignaciones de campos de salida como las asignaciones de campos de proyección del indexador aceptan nodos de árbol de documentos enriquecidos como entradas de origen. Saber cómo especificar una ruta de acceso a cada nodo es esencial para configurar la ruta de acceso de datos. Para obtener más información sobre la sintaxis de ruta de acceso, consulte Referencia a una ruta de acceso a nodos enriquecidos y Definición de conjunto de aptitudes para obtener ejemplos.
Ejecución del indexador
Una vez creados el origen de datos, los índices y el conjunto de aptitudes, ya puede crear y ejecutar el indexador. Este paso pone la canalización en ejecución.
Puede consultar el índice de búsqueda después de que finalice el procesamiento para probar la solución.
Ciclo de vida del contenido
Dependiendo del origen de datos subyacente, un indexador puede proporcionar seguimiento de cambios continuo y detección de borrados. En esta sección se explica el ciclo de vida de contenido de la indexación de uno a varios en relación con la actualización de datos.
Para los orígenes de datos que proporcionan seguimiento de cambios y detección de eliminaciones, un proceso de indexación puede recoger los cambios en sus datos de origen. Cada vez que se ejecutan el indexador y el conjunto de aptitudes, se actualizan las proyecciones de índices si el conjunto de aptitudes o los datos de origen subyacentes han cambiado. Los cambios que recoge el indizador se propagan a través del proceso de enriquecimiento a las proyecciones del índice, lo que garantiza que los datos proyectados sean una representación actual del contenido en el origen de datos de origen. La actividad de actualización de datos se captura en un valor de clave proyectado para cada fragmento. Este valor se actualiza cuando cambian los datos subyacentes.
Nota:
Aunque puede editar manualmente los datos de los documentos proyectados mediante la API de inserción de índice, debe evitar hacerlo. Las actualizaciones manuales de un índice se sobrescriben en la siguiente invocación de canalización, suponiendo que el documento de los datos de origen se actualice y el origen de datos tenga habilitado el seguimiento de cambios o la detección de eliminación.
Contenido actualizado
Si agrega contenido nuevo al origen de datos, se agregan nuevos fragmentos o documentos secundarios al índice en la siguiente ejecución del indexador.
Si modifica el contenido existente en el origen de datos, los fragmentos se actualizan incrementalmente en el índice de búsqueda si el origen de datos que usa admite el seguimiento de cambios y la detección de eliminación. Por ejemplo, si una palabra o frase cambia en un documento, el fragmento del índice de destino que contiene esa palabra u oración se actualiza en la siguiente ejecución del indexador. Otros tipos de actualizaciones, como cambiar un tipo de campo y algunas atribución, no se admiten para campos existentes. Para obtener más información sobre las actualizaciones permitidas, consulte Actualización de un esquema de índice.
Algunos orígenes de datos como Azure Storage admiten el seguimiento de cambios y eliminaciones de forma predeterminada, en función de la marca de tiempo. Otros orígenes de datos, como OneLake, Azure SQLo Azure Cosmos DB deben configurarse para el seguimiento de cambios.
Contenido eliminado
Si el contenido de origen ya no existe (por ejemplo, si el texto se abre para tener menos fragmentos), se elimina el documento secundario correspondiente en el índice de búsqueda. Los documentos secundarios restantes también obtienen su clave actualizada para incluir un nuevo valor hash, incluso si su contenido no ha cambiado de otro modo.
Si un documento primario se elimina completamente del origen de datos, los documentos secundarios correspondientes solo se eliminan si un elemento dataDeletionDetectionPolicy
definido en la definición del origen de datos detecta la eliminación. Si no tiene un elemento dataDeletionDetectionPolicy
configurado y tiene que eliminar un documento primario del origen de datos, debe eliminar manualmente los documentos secundarios si ya no se quieren.
Valor de clave proyectado
Para garantizar la integridad de los datos para el contenido actualizado y eliminado, la actualización de datos en la indexación de uno a varios se basa en un valor de clave proyectado en el lado "varios". Si usa la vectorización integrada o el asistente para importación y vectorización de datos, el valor de clave proyectado es el campo parent_id
en un lado fragmentado o "varios" del índice.
Un valor de clave proyectado es un identificador único que el indexador genera para cada documento. Garantiza la unicidad y permite que el seguimiento de cambios y eliminaciones funcione correctamente. Esta clave contiene los siguientes segmentos:
- Un código hash aleatorio para garantizar la unicidad. Este hash cambia si el documento primario se actualiza en ejecuciones posteriores del indexador.
- Clave del documento primario.
- Ruta de acceso de anotación de enriquecimiento que identifica el contexto desde el que se generó el documento.
Por ejemplo, si divide un documento primario con el valor de clave "aa1b22c33" en cuatro páginas y, a continuación, cada una de esas páginas se proyecta como su propio documento a través de proyecciones de índice:
- aa1b22c33
- aa1b22c33_pages_0
- aa1b22c33_pages_1
- aa1b22c33_pages_2
Si el documento primario se actualiza en los datos de origen, quizás dando lugar a más páginas fragmentadas, el hash aleatorio cambia, se agregan más páginas y el contenido de cada fragmento se actualiza para que coincida con lo que haya en el documento de origen.
Ejemplo de índices primarios y secundarios independientes
En esta sección se muestran ejemplos de índices primarios y secundarios independientes. Es un patrón poco común, pero es posible que tenga requisitos de aplicación que se cumplan mejor usando este enfoque. En este escenario, va a proyectar contenido primario y secundario en dos índices independientes.
Cada esquema tiene los campos para su intervalo de agregación concreto, con el campo de identificador primario común a ambos índices para su uso en una consulta de búsqueda. El corpus de búsqueda principal es el índice secundario, pero después emite una consulta de búsqueda para recuperar los campos primarios de cada coincidencia en el resultado. Búsqueda de Azure AI no admite combinaciones en el momento de la consulta, por lo que el código de la aplicación o la capa de orquestación necesitaría combinar o intercalar los resultados que se pueden pasar a una aplicación o proceso.
El índice primario tiene un campo y un título parent_id. El parent_id es la clave del documento. No necesita la configuración de vector de búsqueda a menos que desee vectorizar campos a nivel de documento primario.
{
"name": "my-parent-index",
"fields": [
{"name": "parent_id", "type": "Edm.String", "filterable": true},
{"name": "title", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "retrievable": true},
]
}
El índice secundario tiene los campos fragmentados, además del campo parent_id. Si usa vectorización integrada, perfiles de puntuación, clasificadores semánticos o analizadores, deberá establecerlos en el índice secundario.
{
"name": "my-child-index",
"fields": [
{"name": "chunk_id", "type": "Edm.String", "key": true, "filterable": true, "analyzer": "keyword"},
{"name": "parent_id", "type": "Edm.String", "filterable": true},
{"name": "chunk", "type": "Edm.String","searchable": true,"retrievable": true},
{"name": "chunk_vector", "type": "Collection(Edm.Single)", "searchable": true, "retrievable": false, "stored": false, "dimensions": 1536, "vectorSearchProfile": "hnsw"}
],
"vectorSearch": {
"algorithms": [{"name": "hsnw", "kind": "hnsw", "hnswParameters": {}}],
"profiles": [{"name": "hsnw", "algorithm": "hnsw"}]
},
"scoringProfiles": [],
"semanticConfiguration": [],
"analyzers": []
}
Este es un ejemplo de una definición de proyección de índice que especifica la ruta de datos que el indexador debe usar para indexar el contenido. Especifica el nombre del índice secundario en la definición de proyección de índice y especifica las asignaciones de cada campo secundario o de nivel de fragmento. Este es el único lugar en el que se especifica el nombre del índice secundario.
"indexProjections": {
"selectors": [
{
"targetIndexName": "my-child-index",
"parentKeyFieldName": "parent_id",
"sourceContext": "/document/pages/*",
"mappings": [
{
"name": "chunk",
"source": "/document/pages/*",
"sourceContext": null,
"inputs": []
},
{
"name": "chunk_vector",
"source": "/document/pages/*/chunk_vector",
"sourceContext": null,
"inputs": []
}
]
}
]
}
La definición del indexador especifica los componentes de la canalización. En la definición del indexador, el nombre del índice que se va a proporcionar es el índice primario. Si necesita asignaciones de campos para los campos de nivel primario, defínalas en outputFieldMappings. En el caso de la indexación de uno a varios que usa índices independientes, la definición del indexador podría ser similar al siguiente ejemplo.
{
"name": "my-indexer",
"dataSourceName": "my-ds",
"targetIndexName": "my-parent-index",
"skillsetName" : "my-skillset"
"parameters": { },
"fieldMappings": (optional) Maps fields in the underlying data source to fields in an index,
"outputFieldMappings" : (required) Maps skill outputs to fields in an index,
}
Paso siguiente
La fragmentación de datos y la indexación de uno a varios forman parte del patrón RAG en Búsqueda de Azure AI. Continúe con el siguiente tutorial y el ejemplo de código para obtener más información.