Определение проекции индекса для индексирования родительского дочернего элемента
Для индексов, содержащих фрагментированные документы, проекция индекса указывает, как содержимое родительского дочернего элемента сопоставляется с полями в индексе поиска для индексирования "один ко многим". С помощью проекции индекса можно отправить содержимое в следующее:
Один индекс, где родительские поля повторяются для каждого блока, но зерно индекса находится на уровне блока. Руководство по RAG является примером этого подхода.
Два или более индексов, где родительский индекс имеет поля, связанные с родительским документом, и дочерний индекс упорядочивается вокруг блоков. Дочерний индекс — это основной корпус поиска, но родительский индекс может использоваться для запросов подстановки, когда требуется получить родительские поля определенного блока или для независимых запросов.
Большинство реализаций — это один индекс, упорядоченный вокруг блоков с родительскими полями, такими как имя файла документа, повторяющийся для каждого блока. Однако система предназначена для поддержки отдельных и нескольких дочерних индексов, если это ваше требование. Поиск по искусственному интеллекту Azure не поддерживает соединения индексов, поэтому код приложения должен обрабатывать используемый индекс.
Проекция индекса определяется в наборе навыков. Он отвечает за координацию процесса индексирования, который отправляет блоки содержимого в индекс поиска, а также родительское содержимое, связанное с каждым блоком. Это улучшает работу блокировок собственных данных, предоставляя дополнительные возможности для управления индексированием содержимого родительского дочернего элемента.
В этой статье объясняется, как создать схему индекса и шаблоны проекции индексатора для индексирования "один ко многим".
Необходимые компоненты
Индекс (один или несколько), который принимает выходные данные конвейера индексатора.
Поддерживаемый источник данных, имеющий содержимое, которое требуется фрагментировать. Это может быть векторное или невекторное содержимое.
Навык, разделяющий содержимое на блоки, навык разделения текста или пользовательский навык, предоставляющий эквивалентную функциональность.
Набор навыков содержит проекцию индексатора, которая формирует данные для индексирования "один ко многим". Набор навыков также может иметь другие навыки, например навык внедрения, например AzureOpenAIEmbedding , если ваш сценарий включает интегрированную векторизацию.
Зависимость от обработки индексатора
Индексирование "один ко многим" зависит от наборов навыков и индексирования на основе индексатора, включающих следующие четыре компонента:
- Источник данных
- Один или несколько индексов для содержимого, доступного для поиска
- Набор навыков, содержащий проекцию индекса*
- Индексатор
Данные могут возникать из любого поддерживаемого источника данных, но предполагается, что содержимое достаточно большое, чтобы его блокировать, и причина его фрагментирования заключается в том, что вы реализуете шаблон RAG, предоставляющий данные о основе для модели чата. Кроме того, вы реализуете векторный поиск и должны соответствовать меньшему размеру входных данных моделей внедрения.
Индексаторы загружают индексированные данные в предопределенный индекс. Определение схемы и использование одного или нескольких индексов является первым решением в сценарии индексирования "один ко многим". В следующем разделе рассматривается проектирование индекса.
Создание индекса для индексирования "один ко многим"
Создаете один индекс для блоков, повторяющих родительские значения или отдельные индексы для размещения полей родительского дочернего элемента, основной индекс, используемый для поиска, предназначен для фрагментов данных. Он должен иметь следующие поля:
Поле ключа документа уникально идентифицирует каждый документ. Он должен быть определен как тип
Edm.String
анализатораkeyword
.Поле, связывающее каждый блок с родительским элементом. Он должен иметь тип
Edm.String
. Оно не может быть полем ключа документа и должноfilterable
иметь значение true. Он называется parent_id в примерах и в качестве проецируемого ключевого значения в этой статье.Другие поля для содержимого, например текстовые или векторизованные поля блока.
Индекс должен существовать в службе поиска перед созданием набора навыков или запуском индексатора.
Одна схема индекса, включаемая в родительские и дочерние поля
Один индекс, разработанный вокруг блоков с родительским содержимым, повторяющимся для каждого блока, является преобладающим шаблоном для сценариев поиска RAG и векторов. Возможность связывания правильного родительского содержимого с каждым блоком включена с помощью проекций индекса.
Следующая схема — это пример, который соответствует требованиям для проекций индексов. В этом примере родительские поля — это parent_id и заголовок. Дочерние поля — это векторные и невекторные блоки. Chunk_id — это идентификатор документа этого индекса. Повторение parent_id и заголовка для каждого блока в индексе.
Для создания индекса можно использовать портал Azure, REST API или пакет SDK Azure.
{
"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"}]
}
}
Добавление проекций индекса в набор навыков
Проекции индекса определяются внутри определения набора навыков и в основном определяются как массив selectors
, где каждый селектор соответствует другому целевому индексу службы поиска. Этот раздел начинается с синтаксиса и примеров контекста, за которым следует ссылка на параметры.
Выберите вкладку для различных синтаксисов API. В настоящее время нет поддержки портала для настройки проекций, кроме редактирования определения набора навыков JSON. Ознакомьтесь с примером REST для JSON.
Прогнозы индекса обычно доступны. Мы рекомендуем самый последний стабильный 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 |
Параметры основного корпуса поиска, как правило, разработанные вокруг блоков. |
projectionMode |
Необязательный параметр, предоставляющий инструкции индексатору. Единственным допустимым значением этого параметра является skipIndexingParentDocuments , и он используется, когда индекс блока является основным корпусом поиска, и необходимо указать, индексируются ли родительские поля в виде дополнительных документов поиска в блокированных индексах. Если вы не задаете skipIndexingParentDocuments , вы получаете дополнительные документы поиска в индексе, которые имеют значение NULL для блоков, но заполнены только родительскими полями. Например, если пять документов вносят 100 блоков в индекс, то число документов в индексе равно 105. В пяти документах, созданных или родительских полях, имеются значения NULL для блоков (дочерних) полей, что значительно отличается от основной части документов в индексе. Рекомендуется projectionMode задать значение skipIndexingParentDocument . |
Селекторы имеют следующие параметры в рамках их определения.
Параметры селектора | Определение |
---|---|
targetIndexName |
Имя индекса, в который проецируются данные индекса. Это либо один блоковый индекс с повторяющимися родительскими полями, либо дочерний индекс, если вы используете отдельные индексы для содержимого родительского дочернего элемента. |
parentKeyFieldName |
Имя поля, предоставляющего ключ родительского документа. |
sourceContext |
Заметка обогащения, определяющая степень детализации, с помощью которой данные сопоставлялись с отдельными документами поиска. Дополнительные сведения см. в разделе Контекст навыка и язык заметок ввода. |
mappings |
Массив сопоставлений обогащенных данных с полями в индексе поиска. Каждое сопоставление состоит из следующих элементов: name : имя поля в индексе поиска, в который должны индексироваться данные. source : Путь заметки обогащения, из который должны быть извлечены данные. Каждый из них mapping также может рекурсивно определять данные с необязательным sourceContext и inputs полем, аналогичным хранилищу знаний или навыку фигуры. В зависимости от приложения эти параметры позволяют формировать данные в поля типа Edm.ComplexType в индексе поиска. Некоторые LLM не принимают сложный тип в результатах поиска, поэтому LLM, который вы используете, определяет, является ли сопоставление сложных типов полезным или нет. |
Параметр mappings
важен. Необходимо явно сопоставить каждое поле в дочернем индексе, за исключением полей идентификатора, таких как ключ документа и родительский идентификатор.
Это требование отличается от других соглашений о сопоставлении полей в поиске ИИ Azure. Для некоторых типов источников данных индексатор может неявно сопоставлять поля на основе аналогичных имен или известных характеристик (например, индексаторы BLOB-объектов используют уникальный путь к хранилищу метаданных в качестве ключа документа по умолчанию). Однако для проекций индексатора необходимо явно указать каждое сопоставление полей на стороне отношения "многие".
Не создавайте сопоставление полей для родительского ключевого поля. Это нарушает отслеживание изменений и синхронизирует обновление данных.
Обработка родительских документов
Теперь, когда вы видели несколько шаблонов для индексирования "один ко многим", позволяет сравнить ключевые различия по каждому варианту. Проекции индекса фактически создают дочерние документы для каждого родительского документа, который выполняется через набор навыков. У вас есть несколько вариантов обработки "родительских" документов.
Чтобы отправить родительские и дочерние документы в отдельные индексы, задайте для определения индексатора родительский индекс и задайте
targetIndexName
targetIndexName
в селекторе проекции индекса дочерний индекс.Чтобы сохранить родительские и дочерние документы в одном индексе, установите индексатор
targetIndexName
и проекциюtargetIndexName
индекса на один и тот же индекс.Чтобы избежать создания родительских документов поиска и обеспечения того, что индекс содержит только дочерние документы единообразного зерна, задайте
targetIndexName
для определения индексатора и селектора один и тот же индекс, но добавьте дополнительныйparameters
объект послеselectors
, с наборомskipIndexingParentDocuments
projectionMode
ключей, как показано ниже:"indexProjections": { "selectors": [ ... ], "parameters": { "projectionMode": "skipIndexingParentDocuments" } }
Просмотр сопоставлений полей
Индексаторы связаны с тремя различными типами сопоставлений полей. Перед запуском индексатора проверьте сопоставления полей и узнайте, когда следует использовать каждый тип.
Сопоставления полей определяются в индексаторе и используются для сопоставления исходного поля с полем индекса. Сопоставления полей используются для путей данных, которые поднимают данные из источника и передают их для индексирования без промежуточного шага обработки навыков. Как правило, индексатор может автоматически сопоставлять поля с одинаковым именем и типом. Явные сопоставления полей требуются только в случае несоответствий. В индексировании "один ко многим" и шаблонах, рассмотренных до сих пор, может не потребоваться сопоставление полей.
Сопоставления полей выходных данных определяются в индексаторе и используются для сопоставления обогащенного содержимого, созданного набором навыков, с полем в основной индекс. В шаблонах "один ко многим", описанных в этой статье, это родительский индекс в решении с двумя индексами. В примерах, показанных в этой статье, родительский индекс разрежен, с полем заголовка, и это поле не заполняется содержимым из обработки набора навыков, поэтому мы не сопоставляем выходные поля.
Сопоставления полей проекции индексатора используются для сопоставления содержимого, созданного набором навыков, полям дочернего индекса. В случаях, когда дочерний индекс также включает родительские поля (как и в консолидированном решении индекса), необходимо настроить сопоставления полей для каждого поля с содержимым, включая поле заголовка родительского уровня, если вы хотите, чтобы заголовок отображался в каждом фрагментованном документе. Если вы используете отдельные родительские и дочерние индексы, проекции индексатора должны иметь сопоставления полей только для полей дочернего уровня.
Примечание.
Сопоставления полей выходных данных и сопоставления полей проекции индексатора принимают обогащенные узлы дерева документов в качестве исходных входных данных. Зная, как указать путь к каждому узлу, важно настроить путь к данным. Дополнительные сведения о синтаксисе пути см. в статье "Справочник по пути к обогащенным узлам и определению набора навыков".
Запуск индексатора
После создания источника данных, индексов и набора навыков вы можете создать и запустить индексатор. Этот шаг помещает конвейер в выполнение.
Вы можете запросить индекс поиска после завершения обработки, чтобы протестировать решение.
Жизненный цикл содержимого
В зависимости от базового источника данных индексатор обычно может предоставлять постоянное обнаружение отслеживания изменений и удаления. В этом разделе объясняется жизненный цикл содержимого индексирования "один ко многим", так как он связан с обновлением данных.
Для источников данных, которые обеспечивают обнаружение отслеживания изменений и удаления, процесс индексатора может получить изменения в исходных данных. При каждом запуске индексатора и набора навыков прогнозы индекса обновляются, если набор навыков или базовые исходные данные изменились. Все изменения, выбранные индексатором, распространяются через процесс обогащения в проекции в индексе, гарантируя, что прогнозируемые данные являются текущим представлением содержимого в исходном источнике данных. Действие обновления данных фиксируется в проецированном значении ключа для каждого блока. Это значение обновляется при изменении базовых данных.
Примечание.
Хотя данные в проецируемых документах можно редактировать вручную с помощью API push-отправки индекса, следует избегать этого. Обновления вручную индекса перезаписываются при следующем вызове конвейера, предполагая, что документ в исходных данных обновляется, а источник данных имеет функцию отслеживания изменений или обнаружения удаления.
Обновленное содержимое
При добавлении нового содержимого в источник данных новые блоки или дочерние документы добавляются в индекс при следующем запуске индексатора.
При изменении существующего содержимого в источнике данных блоки обновляются постепенно в индексе поиска, если используется источник данных, поддерживает обнаружение отслеживания изменений и удаления. Для экзамена, если слово или предложение изменяется в документе, блок в целевом индексе, который содержит это слово или предложение, обновляется при следующем запуске индексатора. Другие типы обновлений, такие как изменение типа поля и некоторые атрибуты, не поддерживаются для существующих полей. Дополнительные сведения о разрешенных обновлениях см. в разделе "Обновление схемы индекса".
Некоторые источники данных, такие как служба хранилища Azure, поддерживают отслеживание изменений и удаления по умолчанию на основе метки времени. Для отслеживания изменений необходимо настроить другие источники данных, такие как OneLake, SQL Azure или Azure Cosmos DB .
Удаленное содержимое
Если исходное содержимое больше не существует (например, если текст сокращен до меньшего количества блоков), соответствующий дочерний документ в индексе поиска удаляется. Остальные дочерние документы также обновляют ключ, чтобы включить новое хэш-значение, даже если его содержимое не изменилось в противном случае.
Если родительский документ полностью удален из источника данных, соответствующие дочерние документы удаляются только в том случае, если удаление обнаружено определенным определением dataDeletionDetectionPolicy
источника данных. Если у вас нет настроенного dataDeletionDetectionPolicy
и необходимо удалить родительский документ из источника данных, удалите дочерние документы вручную, если они больше не нужны.
Значение проецируемого ключа
Чтобы обеспечить целостность данных для обновленного и удаленного содержимого, обновление данных в индексировании "один ко многим" использует проецированное значение ключа на стороне "многие". Если вы используете встроенную векторизацию или мастер импорта и векторизации данных, то проецируемое значение ключа — parent_id
это поле в блокируемой или "много" стороне индекса.
Проецируемый ключ — это уникальный идентификатор, который индексатор создает для каждого документа. Это обеспечивает уникальность и позволяет правильно работать отслеживание изменений и удаления. Этот ключ содержит следующие сегменты:
- Случайный хэш для обеспечения уникальности. Этот хэш изменяется, если родительский документ обновляется при последующих запусках индексатора.
- Ключ родительского документа.
- Путь заметки обогащения, определяющий контекст, из который был создан документ.
Например, если разделить родительский документ со значением ключа "aa1b22c33" на четыре страницы, а затем каждый из этих страниц проецируется в качестве собственного документа с помощью проекций индексов:
- aa1b22c33
- aa1b22c33_pages_0
- aa1b22c33_pages_1
- aa1b22c33_pages_2
Если родительский документ обновляется в исходных данных, возможно, приводит к более фрагментированных страницах, случайные хэш-изменения, добавляются дополнительные страницы, а содержимое каждого блока обновляется, чтобы соответствовать тому, что находится в исходном документе.
Пример отдельных дочерних индексов
В этом разделе показаны примеры отдельных родительских и дочерних индексов. Это необычный шаблон, но возможно, у вас могут быть требования к приложениям, которые лучше всего соответствуют этому подходу. В этом сценарии вы проектируете содержимое родительского дочернего элемента в два отдельных индекса.
Каждая схема имеет поля для определенного зерна, при этом родительское поле идентификатора обычно для обоих индексов для использования в запросе подстановки. Основной корпус поиска является дочерним индексом, но затем выдает запрос подстановки, чтобы получить родительские поля для каждого совпадения в результате. Поиск ИИ Azure не поддерживает соединения во время запроса, поэтому код приложения или слой оркестрации потребуется объединить или сортировать результаты, которые можно передать в приложение или процесс.
Родительский индекс имеет поле parent_id и заголовок. Parent_id — это ключ документа. Вам не нужна конфигурация векторного поиска, если вы не хотите векторизировать поля на родительском уровне документа.
{
"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},
]
}
Дочерний индекс содержит фрагментированные поля, а также поле 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": []
}
Ниже приведен пример определения проекции индекса, указывающего путь к данным индексатора, который должен использовать для индексирования содержимого. Он задает дочернее имя индекса в определении проекции индекса и указывает сопоставления каждого дочернего или блок-уровня поля. Это единственное место, где указано имя дочернего индекса.
"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": []
}
]
}
]
}
Определение индексатора указывает компоненты конвейера. В определении индексатора имя индекса, указываемого является родительским индексом. Если вам нужны сопоставления полей для полей родительского уровня, определите их в 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,
}
Следующий шаг
Блоки данных и индексирование "один ко многим" являются частью шаблона RAG в службе "Поиск ИИ Azure". Перейдите к следующему руководству и примеру кода, чтобы узнать больше об этом.