Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Если вы разбиваете содержимое на фрагменты для шаблона RAG или векторизации, можно указать проекцию индекса для управления индексацией "одного ко многим", где исходное содержимое (одно) распределяется на один или несколько индексов (многие). Цель проекции индекса заключается в том, чтобы управлять элементами родительского документа, например именем файла или датой создания:
- Повторять для каждого дочернего элемента (блок) в одном индексе
- Индексируются как автономные документы поиска в том же индексе
- Или данные загружаются в отдельные индексы
Рекомендуется повторять родительские поля в одном индексе, так как наличие разных фигур документа или разделение содержимого на два индекса может быть трудно запрашивать, особенно в классическом поиске, где соединения индексов не поддерживаются.
В поиске ИИ Azure разбиение выполняется с помощью навыков и поэтому зависит от индексаторов. Чтобы определить проекцию индекса, укажите ее в наборе навыков.
Предварительные требования
Поиск Azure на базе искусственного интеллекта, любой уровень или регион.
Конвейер индексирования на основе индексатора.
Поддерживаемый источник данных, имеющий содержимое, которое требуется фрагментировать.
Индекс (один или несколько), который принимает выходные данные конвейера индексатора.
Навык, который разбивает содержимое на части, например, навык разделения текста.
Набор навыков содержит проекцию индексатора, которая формирует данные для индексирования "один ко многим". Набор навыков также может иметь другие навыки, например навык внедрения, например AzureOpenAIEmbedding , если ваш сценарий включает интегрированную векторизацию.
Выбор подхода
Проекции индекса создают дочерние документы (блоки) для каждого родительского документа. Выберите способ обработки родительского содержимого:
| Подход | Description | Конфигурация |
|---|---|---|
| Один индекс, повторяющиеся родительские поля (рекомендуется) | Родительские поля повторяются для каждого блока. Все документы имеют единую форму. | Задайте для индексатора targetIndexName и проекции targetIndexName индекса одинаковый индекс. Задайте для параметра projectionMode значение skipIndexingParentDocuments. |
| Один индекс, смешанные форматы документа | Родительские документы и фрагменты документов сосуществуют. Родительские документы имеют поля с пустыми блоками. | Задайте для обоих targetIndexName значений одинаковый индекс.
projectionMode Задайте значение includeIndexingParentDocuments (или опустить, так как это значение по умолчанию). |
| Два или более отдельных индексов | Родительский индекс для запросов метаданных, дочерний индекс для поиска. Присоединения в момент запроса отсутствуют. | Установите индексатор targetIndexName для родительского индекса. Задайте индексную проекцию targetIndexName на дочерний индекс. Массив selectors определяет количество и состав дочернего индекса. |
Для большинства сценариев RAG используйте первый подход. См. классический пример RAG.
Шаги реализации для рекомендуемого подхода
- Создайте индекс, предназначенный для блоков, с включенными родительскими полями.
-
Создайте набор навыков с помощью куска навыка и
indexProjections. - Создайте индексатор, указывающий на поддерживаемый источник данных.
Если источник данных поддерживает отслеживание изменений, индексатор автоматически синхронизирует изменения.
Создать индекс для метода индексирования "один ко многим"
Создаете один индекс для блоков, повторяющих родительские значения или отдельные индексы для размещения полей родительского дочернего элемента, основной индекс, используемый для поиска, предназначен для фрагментов данных. Схема индекса должна иметь следующие поля:
Поле ключа документа уникально идентифицирует каждый документ. Это должно быть определено как тип
Edm.String, используя анализаторkeyword.Поле, связывающее каждый блок с родительским элементом. Он должен иметь тип
Edm.String. Оно не может быть полем ключа документа и должноfilterableиметь значение true. Он называется parent_id в примерах и в качестве проецируемого ключевого значения в этой статье.Другие поля для содержимого, такие как текстовые или векторизованные поля фрагмента.
Индекс должен существовать в службе поиска перед созданием набора навыков или запуском индексатора. Определяемые selectors в наборе навыков должны включать эти поля.
Одна схема индекса, включая родительские и дочерние поля
Один индекс, разработанный вокруг блоков с родительским содержимым, повторяющимся для каждого блока, является преобладающим шаблоном для сценариев поиска RAG и векторов. Возможность связать корректное родительское содержимое с каждым фрагментом обеспечивается проекциями индекса.
Следующая схема — это пример, который соответствует требованиям для проекций индексов. В этом примере:
- Родительские поля — это parent_id и заголовок, и они повторяются для каждого блока.
- Дочерние поля — это векторные и невекторные блоки. Chunk_id — это идентификатор документа этого индекса.
Для создания индекса можно использовать портал Azure, REST API или пакет SDK Azure.
Чтобы создать индекс, используйте REST-клиент или портал Azure и действие Добавить индекс с опцией JSON.
{
"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": "hnsw", "kind": "hnsw", "hnswParameters": {}}],
"profiles": [{"name": "hnsw", "algorithm": "hnsw"}]
}
}
Добавление проекций индекса в набор навыков
Проекции индекса определяются внутри определения набора навыков и в основном определяются как массив selectors, где каждый селектор соответствует другому целевому индексу службы поиска. Этот раздел начинается с синтаксиса и примеров контекста, за которым следует ссылка на параметры.
Прогнозы индекса обычно доступны. Мы рекомендуем самый последний стабильный API:
Ниже приведен пример полезной нагрузки для определения проекции индекса, которую можно использовать для того, чтобы проецировать отдельные страницы, создаваемые с помощью навыка "разделение текста", как отдельные документы в поисковом индексе.
"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"
}
}
Референс параметров
| Параметры проекции индекса | Определение |
|---|---|
selectors |
Массив с параметрами основного поискового корпуса, обычно индекс, разработанный на основе сегментов. Содержимое можно отправить нескольким дочерним индексам, указав несколько селекторов. Схемы индекса должны существовать в службе поиска перед запуском индексатора. |
parameters |
Словарь конфигурационных параметров, специфичных для проекции индекса. |
Параметры имеют следующие элементы в рамках их определения.
| Параметры | Определение |
|---|---|
parameters.projectionMode |
Необязательный параметр, предоставляющий инструкции индексатору. Допустимые значения включают includeIndexingParentDocuments и skipIndexingParentDocuments. Лучшее значение для этого параметра — skipIndexingParentDocuments. Его следует использовать, когда разделенные на части документы являются основным объектом поиска. Если вы не зададите skipIndexingParentDocuments для projectionMode, вы получите includeIndexingParentDocuments автоматически, так как это значение по умолчанию. Он добавляет дополнительные документы поиска в индекс, которые имеют значение NULL для блоков, но заполнены родительским содержимым. Например, если пять PDF-файлов вносят 100 блоков в индекс, то количество документов в индексе равно 105. Пять документов, созданных для родительских полей, имеют значения NULL для полей блока (дочернего), что значительно отличается от основной части документов в индексе. По этой причине мы рекомендуем projectionMode установить на значение skipIndexingParentDocuments. |
Селекторы имеют следующие элементы в рамках их определения.
| Селекторы | Определение |
|---|---|
selectors.targetIndexName |
Имя индекса, в который проецируются данные индекса. Это либо один блоковый индекс с повторяющимися родительскими полями, либо дочерний индекс, если вы используете отдельные индексы для содержимого родительского дочернего элемента. |
selectors.parentKeyFieldName |
Имя поля, предоставляющего ключ родительского документа. |
selectors.sourceContext |
Аннотация обогащения, определяющая гранулярность, с которой данные проецируются на отдельные документы поиска. Дополнительные сведения см. в разделе Контекст навыка и язык заметок ввода. |
selectors.mappings |
Массив сопоставлений обогащенных данных с полями в индексе поиска. Каждое сопоставление состоит из следующих элементов: name: имя поля в индексе поиска, в который должны индексироваться данные. source: Путь аннотации обогащения, из которого должны быть извлечены данные. Каждый mapping также может рекурсивно определять данные с необязательным sourceContext и inputs полем, аналогичным хранилищу знаний или навыку фигуры. В зависимости от приложения эти параметры позволяют формировать данные в поля типа Edm.ComplexType в индексе поиска. Некоторые LLM не принимают сложный тип в результатах поиска, поэтому LLM, который вы используете, определяет, является ли сопоставление сложных типов полезным или нет. |
Параметр mappings важен. Необходимо явно сопоставить каждое поле в дочернем индексе, за исключением полей идентификатора, таких как ключ документа и родительский идентификатор.
Это требование отличается от других соглашений о сопоставлении полей в поиске ИИ Azure. Для некоторых типов источников данных индексатор может неявно сопоставлять поля на основе аналогичных имен или известных характеристик (например, индексаторы BLOB-объектов используют уникальный путь к хранилищу метаданных в качестве ключа документа по умолчанию). Однако для проекций индексатора необходимо явно указать каждое сопоставление полей на стороне отношения "многие".
Это важно
Не создавайте сопоставление полей для родительского ключевого поля. Это нарушает отслеживание изменений и препятствует синхронизированному обновлению данных.
Просмотр сопоставлений полей
Индексаторы связаны с тремя различными типами сопоставлений полей. Перед запуском индексатора проверьте сопоставления полей и узнайте, когда следует использовать каждый тип.
Сопоставления полей определяются в индексаторе и используются для сопоставления исходного поля с полем индекса. Сопоставления полей используются для путей данных, которые поднимают данные из источника и передают их для индексирования без промежуточного шага обработки навыков. Как правило, индексатор может автоматически сопоставлять поля с одинаковым именем и типом. Явные сопоставления полей требуются только в случае несоответствий. В индексировании "один ко многим" и шаблонах, рассмотренных до сих пор, может не потребоваться сопоставление полей.
Сопоставления выходных полей определяются в индексаторе и используются для сопоставления обогащенного содержимого, созданного набором навыков, с полем в главный индекс. Фрагменты считаются обогащенным контентом благодаря созданию с помощью навыка (Text Split). Однако для фрагментов или проекций индекса, определяемых сопоставлением селектора, не требуется сопоставление выходных полей.
Селекторы.сопоставления определяются в наборе навыков и сопоставляются с полями в дочернем индексе. В случаях, когда дочерний индекс также включает родительские поля (как и в консолидированном решении индекса), необходимо настроить сопоставления полей для каждого поля с содержимым, включая поле заголовка родительского уровня, если вы хотите, чтобы заголовок отображался в каждом фрагментованном документе. Если вы используете отдельные родительские и дочерние индексы, селектор должен иметь сопоставления полей только для полей дочернего уровня.
Примечание.
Сопоставления выходных полей и сопоставления селекторов принимают обогащенные узлы дерева документов в качестве исходных входных данных. Зная, как указать путь к каждому узлу, важно настроить путь к данным. Дополнительные сведения о синтаксисе пути см. в Справочнике по пути к обогащенным узлам и в определении набора навыков для примеров.
Запуск индексатора
После создания источника данных, индексов и набора навыков вы можете создать и запустить индексатор. Этот шаг помещает конвейер в выполнение.
Вы можете запросить индекс поиска после завершения обработки, чтобы протестировать решение.
Жизненный цикл содержимого
В зависимости от базового источника данных индексатор обычно может предоставлять постоянное отслеживание изменений и обнаружение удаления. В этом разделе объясняется жизненный цикл содержимого индексирования "один ко многим", так как он связан с обновлением данных.
Для источников данных, которые обеспечивают отслеживание изменений и обнаружение удалений, процесс индексатора может принимать изменения в исходных данных. При каждом запуске индексатора и набора навыков прогнозы индекса обновляются, если набор навыков или базовые исходные данные изменились. Все изменения, обнаруженные индексатором, распространяются через процесс обогащения к проекциям в индексе, гарантируя, что проецируемые данные являются актуальным представлением содержимого в исходном источнике данных. Действие обновления данных фиксируется в проецированном значении ключа для каждого блока. Это значение обновляется при изменении базовых данных.
Примечание.
Хотя данные в проецируемых документах можно редактировать вручную с помощью API push-отправки индекса, следует избегать этого. Вручные обновления индекса перезаписываются при следующем вызове пайплайна, при условии, что документ в исходных данных обновляется, а источник данных поддерживает функцию отслеживания изменений или выявления удаления.
Обновленное содержимое
При добавлении нового содержимого в источник данных новые блоки или дочерние документы добавляются в индекс при следующем запуске индексатора.
При изменении существующего содержимого в источнике данных блоки в индексе поиска обновляются поэтапно, если используемый источник данных поддерживает отслеживание изменений и обнаружение удаления. Например, если слово или предложение изменяется в документе, блок в целевом индексе, который содержит это слово или предложение, обновляется при следующем запуске индексатора. Другие типы обновлений, такие как изменение типа поля и некоторые атрибуты, не поддерживаются для существующих полей. Дополнительные сведения о разрешенных обновлениях см. в разделе "Обновление схемы индекса".
Некоторые источники данных, такие как служба хранилища Azure, поддерживают отслеживание изменений и удаления по умолчанию на основе метки времени. Другие источники данных, такие как Microsoft OneLake, SQL Azure или Azure Cosmos DB , должны быть настроены для отслеживания изменений.
Удаленное содержимое
Если исходное содержимое больше не существует (например, если текст сокращен до меньшего количества блоков), соответствующий дочерний документ в индексе поиска удаляется. Оставшиеся дочерние документы также получают обновленный ключ, чтобы добавить новое хэш-значение, даже если их содержание осталось неизменным.
Если родительский документ полностью удален из источника данных, соответствующие дочерние документы удаляются только в том случае, если удаление обнаружено определенным определением dataDeletionDetectionPolicy источника данных. Если у вас нет настроенного dataDeletionDetectionPolicy и необходимо удалить родительский документ из источника данных, удалите дочерние документы вручную , если они больше не нужны.
Значение проецируемого ключа
Чтобы обеспечить целостность данных для обновленного и удаленного содержимого, обновление данных в индексировании "один ко многим" использует проецированное значение ключа на стороне "многие". Если вы используете встроенную векторизацию или мастер импорта данных, то проецируемое значение ключа — parent_id это поле в фрагментируемой или "много" стороне индекса.
Проецируемый ключ — это уникальный идентификатор, который индексатор создает для каждого документа. Это обеспечивает уникальность и позволяет корректно отслеживать изменения и удаления. Этот ключ содержит следующие сегменты:
- Случайный хэш для обеспечения уникальности. Этот хэш изменяется, если родительский документ обновляется при последующих запусках индексатора.
- Ключ родительского документа.
- Путь аннотации обогащения, который определяет контекст для сгенерированного документа.
Например, если разделить родительский документ со значением ключа "aa1b22c33" на четыре страницы, а затем каждый из этих страниц проецируется в качестве собственного документа с помощью проекций индексов:
- aa1b22c33
- aa1b22c33_pages_0
- aa1b22c33_pages_1
- aa1b22c33_pages_2
Если родительский документ обновляется в исходных данных, это, возможно, приводит к более фрагментированным страницам, случайные изменения хэша, добавляется больше страниц, а содержимое каждого блока обновляется, чтобы соответствовать исходному документу.
Пример отдельных индексов родителя и ребенка
В этом разделе показан пример отдельных родительских и дочерних индексов. Это необычный шаблон, но возможно, у вас могут быть требования к приложениям, которые лучше всего соответствуют этому подходу. В этом сценарии вы переносите содержимое в родительских и дочерних индексах в два отдельных контейнера.
Создайте две схемы индекса.
Каждая схема имеет поля для своего конкретного уровня детализации, при этом родительское поле ID, общее для обоих индексов, используется в запросе поиска. Основной корпус поиска является дочерним индексом, но вы можете выполнить запрос подстановки, чтобы получить родительские поля для каждого совпадения в результате. Поиск ИИ Azure не поддерживает операции соединения во время запроса, поэтому код приложения или слоя оркестрации потребуется объединить или агрегировать результаты, которые можно передать в приложение или процесс.
Родительский индекс имеет поле parent_id и заголовок. Parent_id — это ключ документа. Вам не нужна конфигурация векторного поиска, если вы не хотите векторизировать поля на родительском уровне документа.
{ "name": "my-parent-index", "fields": [ {"name": "parent_id", "type": "Edm.String", "key":true, "filterable": true}, {"name": "title", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "retrievable": true} ] }Дочерний индекс содержит фрагментированные поля, а также поле parent_id. Если вы используете встроенную векторизацию, профили оценки, семантический ранжировщик или анализаторы, вы задаете их в дочернем индексе.
{ "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": [] }Обновите индексатор, чтобы указать родительский индекс в качестве целевого объекта.
Определение индексатора указывает компоненты конвейера. В определении индексатора имя индекса, указываемого является родительским индексом. Если вам нужны сопоставления полей для полей родительского уровня, определите их в outputFieldMappings. Для индексирования "один ко многим", использующего отдельные индексы, определение индексатора может выглядеть следующим образом.
{ "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, }Добавьте
indexProjectionsв набор навыков.Ниже приведен пример определения проекции индекса, указывающего путь к данным индексатора, который должен использовать для индексирования содержимого. Он задает имя дочернего индекса в определении проекции индекса и указывает сопоставления каждого дочернего поля или уровня сегмента. Это единственное место, где указано имя дочернего индекса.
Обратите внимание, что
parametersявляется null и оно использует значение по умолчаниюincludeIndexingParentDocuments. Индексатор заполняет родительский индекс. Массивselectorsиспользуется для проецирования фрагментов документов в дочерний индекс."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": [] } ] } ], "parameters": {} }Запустите индексатор. Если вы ранее запустили индексатор, сначала не забудьте сбросить его.
У вас должно быть два индекса, заполненных соответствующим содержимым. Запросите индексы в обозревателе поиска, чтобы убедиться, что каждый из них содержит правильное содержимое.
Следующий шаг
Разбиение данных на сегменты и индексирование "один ко многим" являются частью классического шаблона RAG в службе Azure AI Search. Перейдите к следующему руководству и примеру кода, чтобы узнать больше об этом.