Поделиться через


Manage indexing policies in Azure Cosmos DB (Управление политиками индексирования в Azure Cosmos DB)

В Azure Cosmos DB данные индексируются после политик индексирования , определенных для каждого контейнера. Политика индексирования по умолчанию, задаваемая для только что созданных контейнеров, применяет диапазонные индексы для любых строк или чисел. Эту политику можно переопределить с помощью собственной настраиваемой политики индексирования.

Примечание.

Метод обновления политик индексирования, описанных в этой статье, применяется только к Azure Cosmos DB для NoSQL. Узнайте об индексировании в Azure Cosmos DB для MongoDB и вторичном индексировании в Azure Cosmos DB для Apache Cassandra.

Примеры политик индексирования

Ниже приведены некоторые примеры политик индексирования, отображаемых в формате JSON. Они предоставляются в портал Azure в формате JSON. Те же параметры можно задать с помощью Azure CLI или любого пакета SDK.

Политика отказа для выборочного исключения определённых путей к свойствам

{
    "indexingMode": "consistent",
    "includedPaths": [
        {
            "path": "/*"
        }
    ],
    "excludedPaths": [
        {
            "path": "/path/to/single/excluded/property/?"
        },
        {
            "path": "/path/to/root/of/multiple/excluded/properties/*"
        }
    ]
}

Примечание.

  • Ключ секции (если только он также не является /id) не индексируется и должен быть включен в индекс.
  • Системные свойства id и _ts всегда индексируются при использовании режима consistentиндексирования учетной записи Cosmos.
  • Системные свойства id и _ts не включены в описание индексированных путей политики контейнера. Это связано с тем, что эти системные свойства индексируются по умолчанию, и это поведение не может быть отключено.

Политика согласия для выборочного включения некоторых путей к свойствам

{
    "indexingMode": "consistent",
    "includedPaths": [
        {
            "path": "/path/to/included/property/?"
        },
        {
            "path": "/path/to/root/of/multiple/included/properties/*"
        }
    ],
    "excludedPaths": [
        {
            "path": "/*"
        }
    ]
}

Примечание.

Мы обычно рекомендуем использовать политику индексирования типа отказа от участия. Azure Cosmos DB заранее индексирует любое новое свойство, которое может быть добавлено в модель данных.

Использование пространственного индекса только для определенного пути свойства

{
    "indexingMode": "consistent",
    "automatic": true,
    "includedPaths": [
        {
            "path": "/*"
        }
    ],
    "excludedPaths": [
        {
            "path": "/_etag/?"
        }
    ],
    "spatialIndexes": [
        {
                    "path": "/path/to/geojson/property/?",
            "types": [
                "Point",
                "Polygon",
                "MultiPolygon",
                "LineString"
            ]
        }
    ]
}

Примеры политики индексирования векторов

Помимо включения или исключения путей для отдельных свойств, можно также указать векторный индекс. Как правило, индексы векторов следует указывать всякий раз, когда VectorDistance системная функция используется для измерения сходства между вектором запроса и свойством вектора.

Примечание.

Прежде чем продолжить, необходимо включить индексирование и поиск векторов NoSQL в Azure Cosmos DB.

Внимание

Политика индексирования векторов должна находиться в том же пути, который определен в политике вектора контейнера. Дополнительные сведения см. в разделе "Политики вектора контейнеров".

{
    "indexingMode": "consistent",
    "automatic": true,
    "includedPaths": [
        {
            "path": "/*"
        }
    ],
    "excludedPaths": [
        {
            "path": "/_etag/?"
        }
    ],
    "vectorIndexes": [
        {
            "path": "/vector",
            "type": "quantizedFlat"
        }
    ]
}

Внимание

Символы подстановочных карточек (*, []) и векторные пути, вложенные внутри массивов, в настоящее время не поддерживаются в политике векторов или векторном индексе.

Внимание

В настоящее время политики векторов и векторные индексы неизменяемы после создания. Чтобы внести изменения, создайте новую коллекцию.

Можно определить следующие типы политик векторного индекса:

Тип Описание Максимальные размеры
flat Сохраняет векторы в том же индексе, что и другие индексированные свойства. 505
quantizedFlat Квантизует (сжимает) векторы перед хранением в индексе. Это может повысить задержку и пропускную способность за счет небольшого количества точности. 4096
diskANN Создает индекс на основе DiskANN для быстрого и эффективного поиска. 4096

flat и quantizedFlat типы индексов используют индекс Azure Cosmos DB для хранения и чтения каждого вектора при выполнении векторного поиска. Поиск векторов с индексом flat осуществляется полным перебором и обеспечивает 100% точность. Однако существует ограничение 505 измерений для векторов на плоском индексе.

Индекс quantizedFlat сохраняет квантизованные или сжатые векторы в индексе. Векторный поиск с использованием quantizedFlat индекса также является поиском методом прямого перебора, однако его точность может быть немного меньше 100%, так как векторы квантуируются перед добавлением в индекс. Однако при поиске векторов с quantized flat задержка должна быть ниже, пропускная способность выше, а стоимость ЕЗ ниже, чем при векторных поисках по индексу flat. Это хороший вариант для сценариев, в которых вы используете фильтры запросов, чтобы сузить векторный поиск до относительно небольшого набора векторов.

Индекс diskANN — это отдельный индекс, определенный специально для векторов с помощью DiskANN, набора высокопроизводительных алгоритмов индексирования векторов, разработанных Microsoft Research. Индексы DiskANN могут предложить одни из самых низких задержек, наивысшее число запросов в секунду (QPS) и наименьшую стоимость запросов в RU при высокой точности. Однако, так как DiskANN является приблизительным ближайшим индексом соседей (ANN), точность может быть ниже quantizedFlat или flat.

Индексы diskANN и quantizedFlat могут принимать необязательные параметры сборки индекса, которые можно использовать для настройки компромисса между точностью и задержкой, применяемого к каждому индексу вектора ANN.

  • quantizationByteSize: задает размер (в байтах) для квантизации продукта: Min=1, Default=dynamic (решение системы), Max=512. Установка более высокого значения может привести к повышенной точности векторного поиска за счет более высокой RU-стоимости и задержки. Это относится к обоим типам индексов quantizedFlat и DiskANN.
  • indexingSearchListSize: задает количество векторов для поиска во время построения индекса: Min=10, Default=100, Max=500. Установка этого большего размера может привести к более точному поиску векторов за счет более длительного времени сборки индекса и более высокой задержки приема векторов. Это относится только к DiskANN индексам.

Использование сегментированного diskANN

Сегментированная служба DiskANN помогает оптимизировать крупномасштабный векторный поиск, разделив индекс DiskANN на меньшие, более управляемые части. Указав VectorIndexShardKey в политике индексирования контейнера, можно создать несколько индексов DiskANN — по одному для каждого уникального значения выбранного свойства документа.

Такой подход может привести к более быстрому выполнению запросов, улучшению поиска и снижению затрат на RU, особенно при работе с данными с высокой кардинальностью. Независимо от того, создаете ли вы подсистемы рекомендаций, семантический поиск или интеллектуальные агенты, сегментированный DiskANN дает вам больше контроля над структурой и выполнением индексирования векторов.

Здесь можно увидеть пример определения ключа сегментов на основе свойства tenantID. Это может быть любое свойство элемента данных, даже ключа раздела. Одна строка должна быть заключена в массив. Дополнительные сведения см. в статье Sharded DiskANN: поиск вектора с фокусом.

"vectorIndexes": [
    {
        "path": "/vector2",
        "type": "DiskANN",
        "vectorIndexShardKey": ["/tenantID"]
    }
]

Примеры политики индексирования кортежей

В этом примере политика индексирования определяет индекс кортежа на events.name и events.category.

{  
    "automatic":true,
    "indexingMode":"Consistent",
    "includedPaths":[  
        {"path":"/*"}, 
        {"path":"/events/[]/{name,category}/?"} 
    ],
    "excludedPaths":[],
    "compositeIndexes":[]
}

Предыдущий индекс используется для следующего запроса.

SELECT * 
FROM root r 
WHERE 
   EXISTS (SELECT VALUE 1 FROM ev IN r.events 
           WHERE ev.name = 'M&M' AND ev.category = 'Candy') 

Примеры политик составного индексирования

Кроме добавления и удаления путей отдельных свойств, вы также можете указать составной индекс. Для выполнения запроса, содержащего условие для нескольких свойств, требуется составной индекс для этих свойств. Если запрос включает фильтры вместе с сортировкой по нескольким свойствам, может потребоваться несколько составных индексов.

Составные индексы также имеют преимущество производительности для запросов с несколькими фильтрами или как фильтром, так и предложением ORDER BY.

Примечание.

Составные пути имеют неявный подстановочный знак /?, так как в этих путях индексируется только скалярное значение. Метасимвол /* не поддерживается в составных путях. В составном пути не следует указывать /? и /*. Составные пути также чувствительны к регистру.

Составной индекс, определенный для (имя по возрастанию, возраст по убыванию)

{  
    "automatic":true,
    "indexingMode":"Consistent",
    "includedPaths":[  
        {  
            "path":"/*"
        }
    ],
    "excludedPaths":[],
    "compositeIndexes":[  
        [  
            {  
                "path":"/name",
                "order":"ascending"
            },
            {  
                "path":"/age",
                "order":"descending"
            }
        ]
    ]
}

Составной индекс имени и возраста требуется для следующих запросов:

Запрос #1:

SELECT *
FROM c
ORDER BY c.name ASC, c.age DESC

Запрос #2:

SELECT *
FROM c
ORDER BY c.name DESC, c.age ASC

Этот составной индекс обеспечивает следующие запросы и оптимизирует фильтры:

Запрос #3:

SELECT *
FROM c
WHERE c.name = "Tim"
ORDER BY c.name DESC, c.age ASC

Запрос #4:

SELECT *
FROM c
WHERE c.name = "Tim" AND c.age > 18

Составной индекс, определенный для (имя ASC, возраст ASC) и (имя ASC, возраст DESC)

Можно определить несколько составных индексов в одной политике индексирования.

{  
    "automatic":true,
    "indexingMode":"Consistent",
    "includedPaths":[  
        {  
            "path":"/*"
        }
    ],
    "excludedPaths":[],
    "compositeIndexes":[  
        [  
            {  
                "path":"/name",
                "order":"ascending"
            },
            {  
                "path":"/age",
                "order":"ascending"
            }
        ],
        [  
            {  
                "path":"/name",
                "order":"ascending"
            },
            {  
                "path":"/age",
                "order":"descending"
            }
        ]
    ]
}

Составной индекс, определенный для (имя ASC, возраст ASC)

Необязательно указать порядок. Если он не указан, по умолчанию используется порядок по возрастанию.

{  
    "automatic":true,
    "indexingMode":"Consistent",
    "includedPaths":[  
        {  
            "path":"/*"
        }
    ],
    "excludedPaths":[],
    "compositeIndexes":[  
        [  
            {  
               "path":"/name"
            },
            {  
               "path":"/age"
            }
        ]
    ]
}

Исключите все пути свойств, но сохраняйте активное индексирование

Эту политику можно использовать, когда функция времени жизни (TTL) активна, но другие индексы не необходимы для использования Azure Cosmos DB в качестве чистого хранилища значений ключей.

{
    "indexingMode": "consistent",
    "includedPaths": [],
    "excludedPaths": [{
        "path": "/*"
    }]
}

Без индексирования

Эта политика отключает индексирование. Если indexingMode задано значение none, вы не можете задать TTL в контейнере.

{
    "indexingMode": "none"
}

Обновление политики индексирования

В Azure Cosmos DB политика индексирования может быть обновлена с помощью любого из следующих методов:

  • На портале Azure
  • Использование Azure CLI
  • Использование PowerShell
  • Использование одного из пакетов SDK

Обновление политики индексирования активирует преобразование индекса. Ход выполнения этого преобразования также можно отслеживать с помощью пакетов SDK.

Примечание.

При обновлении политики индексирования запись в Azure Cosmos DB не прерывается. Дополнительные сведения о преобразованиях индексирования.

Внимание

Удаление индекса вступает в силу немедленно, тогда как добавление нового индекса занимает некоторое время, так как требуется преобразование индексирования. При замене одного индекса другим (например, заменив один индекс свойств составным индексом), сначала добавьте новый индекс, а затем дождитесь завершения преобразования индекса перед удалением предыдущего индекса из политики индексирования. В противном случае это негативно влияет на способность запрашивать предыдущий индекс и может нарушить любые активные рабочие нагрузки, ссылающиеся на предыдущий индекс.

Использование портала Azure

Контейнеры Azure Cosmos DB хранят политику индексирования в виде документа JSON, который портал Azure позволяет напрямую редактировать.

  1. Войдите на портал Azure.

  2. Создайте новую учетную запись Azure Cosmos DB или выберите существующую учетную запись.

  3. Откройте область обозревателя данных и выберите контейнер, над которыми вы хотите работать.

  4. Выберите "Параметры", а затем выберите "Политика индексирования".

  5. Измените документ JSON политики индексирования, как показано в этих примерах.

  6. Нажмите кнопку "Сохранить " после завершения.

Снимок экрана: управление индексированием с помощью портала Azure.

Использование командной строки Azure CLI

Сведения о создании контейнера с настраиваемой политикой индексирования см. в статье "Создание контейнера с настраиваемой политикой индекса с помощью ИНТЕРФЕЙСА командной строки".

С помощью PowerShell

Сведения о создании контейнера с настраиваемой политикой индексирования см. в статье "Создание контейнера с настраиваемой политикой индекса с помощью PowerShell".

Использование пакета SDK для .NET

Объект ContainerProperties из пакета SDK для .NET версии 3 предоставляет IndexingPolicy свойство, которое позволяет изменять IndexingMode и добавлять или удалятьIncludedPaths.ExcludedPaths Дополнительные сведения см. в руководстве по быстрому началу работы: использование Azure Cosmos DB для NoSQL с пакетом Azure SDK для .NET.

// Retrieve the container's details
ContainerResponse containerResponse = await client.GetContainer("database", "container").ReadContainerAsync();
// Set the indexing mode to consistent
containerResponse.Resource.IndexingPolicy.IndexingMode = IndexingMode.Consistent;
// Add an included path
containerResponse.Resource.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
// Add an excluded path
containerResponse.Resource.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/name/*" });
// Add a spatial index
SpatialPath spatialPath = new SpatialPath
{
    Path = "/locations/*"
};
spatialPath.SpatialTypes.Add(SpatialType.Point);
containerResponse.Resource.IndexingPolicy.SpatialIndexes.Add(spatialPath);
// Add a composite index
containerResponse.Resource.IndexingPolicy.CompositeIndexes.Add(new Collection<CompositePath> { new CompositePath() { Path = "/name", Order = CompositePathSortOrder.Ascending }, new CompositePath() { Path = "/age", Order = CompositePathSortOrder.Descending } });
// Update container with changes
await client.GetContainer("database", "container").ReplaceContainerAsync(containerResponse.Resource);

Чтобы отслеживать ход выполнения преобразования индекса, передайте объект RequestOptions, который задает для свойства PopulateQuotaInfo значение true. Получите значение из заголовка x-ms-documentdb-collection-index-transformation-progress ответа.

// retrieve the container's details
ContainerResponse containerResponse = await client.GetContainer("database", "container").ReadContainerAsync(new ContainerRequestOptions { PopulateQuotaInfo = true });
// retrieve the index transformation progress from the result
long indexTransformationProgress = long.Parse(containerResponse.Headers["x-ms-documentdb-collection-index-transformation-progress"]);

Fluent API SDK версии 3 позволяет написать это определение в краткой и эффективной форме при определении пользовательской политики индексирования при создании нового контейнера.

await client.GetDatabase("database").DefineContainer(name: "container", partitionKeyPath: "/myPartitionKey")
    .WithIndexingPolicy()
        .WithIncludedPaths()
            .Path("/*")
        .Attach()
        .WithExcludedPaths()
            .Path("/name/*")
        .Attach()
        .WithSpatialIndex()
            .Path("/locations/*", SpatialType.Point)
        .Attach()
        .WithCompositeIndex()
            .Path("/name", CompositePathSortOrder.Ascending)
            .Path("/age", CompositePathSortOrder.Descending)
        .Attach()
    .Attach()
    .CreateIfNotExistsAsync();

Использование пакета SDK для Java

Объект DocumentCollection из пакета SDK для Java предоставляет getIndexingPolicy() методы и setIndexingPolicy() методы. Объект IndexingPolicy, которым они управляют, позволяет изменить режим индексирования и добавить или удалить включенные и исключенные пути. Дополнительные сведения см. в кратком руководстве: Использование Azure Cosmos DB для NoSQL с Azure SDK для Java.

// Retrieve the container's details
Observable<ResourceResponse<DocumentCollection>> containerResponse = client.readCollection(String.format("/dbs/%s/colls/%s", "database", "container"), null);
containerResponse.subscribe(result -> {
DocumentCollection container = result.getResource();
IndexingPolicy indexingPolicy = container.getIndexingPolicy();

// Set the indexing mode to consistent
indexingPolicy.setIndexingMode(IndexingMode.Consistent);

// Add an included path

Collection<IncludedPath> includedPaths = new ArrayList<>();
IncludedPath includedPath = new IncludedPath();
includedPath.setPath("/*");
includedPaths.add(includedPath);
indexingPolicy.setIncludedPaths(includedPaths);

// Add an excluded path

Collection<ExcludedPath> excludedPaths = new ArrayList<>();
ExcludedPath excludedPath = new ExcludedPath();
excludedPath.setPath("/name/*");
excludedPaths.add(excludedPath);
indexingPolicy.setExcludedPaths(excludedPaths);

// Add a spatial index

Collection<SpatialSpec> spatialIndexes = new ArrayList<SpatialSpec>();
Collection<SpatialType> collectionOfSpatialTypes = new ArrayList<SpatialType>();

SpatialSpec spec = new SpatialSpec();
spec.setPath("/locations/*");
collectionOfSpatialTypes.add(SpatialType.Point);
spec.setSpatialTypes(collectionOfSpatialTypes);
spatialIndexes.add(spec);

indexingPolicy.setSpatialIndexes(spatialIndexes);

// Add a composite index

Collection<ArrayList<CompositePath>> compositeIndexes = new ArrayList<>();
ArrayList<CompositePath> compositePaths = new ArrayList<>();

CompositePath nameCompositePath = new CompositePath();
nameCompositePath.setPath("/name");
nameCompositePath.setOrder(CompositePathSortOrder.Ascending);

CompositePath ageCompositePath = new CompositePath();
ageCompositePath.setPath("/age");
ageCompositePath.setOrder(CompositePathSortOrder.Descending);

compositePaths.add(ageCompositePath);
compositePaths.add(nameCompositePath);

compositeIndexes.add(compositePaths);
indexingPolicy.setCompositeIndexes(compositeIndexes);

// Update the container with changes

 client.replaceCollection(container, null);
});

Чтобы отслеживать ход преобразования индекса в контейнере, передайте объект RequestOptions, который запрашивает сведения о квоте для заполнения. Получите значение из заголовка x-ms-documentdb-collection-index-transformation-progress ответа.

// set the RequestOptions object
RequestOptions requestOptions = new RequestOptions();
requestOptions.setPopulateQuotaInfo(true);
// retrieve the container's details
Observable<ResourceResponse<DocumentCollection>> containerResponse = client.readCollection(String.format("/dbs/%s/colls/%s", "database", "container"), requestOptions);
containerResponse.subscribe(result -> {
    // retrieve the index transformation progress from the response headers
    String indexTransformationProgress = result.getResponseHeaders().get("x-ms-documentdb-collection-index-transformation-progress");
});

Использование пакета SDK для Node.js

Интерфейс ContainerDefinition из пакета SDKNode.js предоставляет indexingPolicy свойство, которое позволяет изменять indexingMode, а также добавлять или удалять includedPaths и excludedPaths. Дополнительные сведения см. в руководстве по быстрому старту: использование Azure Cosmos DB для NoSQL с Azure SDK для Node.js.

Получение сведений о контейнере:

const containerResponse = await client.database('database').container('container').read();

Задайте для режима индексирования согласованность:

containerResponse.body.indexingPolicy.indexingMode = "consistent";

Добавьте включенный путь, включая пространственный индекс:

containerResponse.body.indexingPolicy.includedPaths.push({
    includedPaths: [
      {
        path: "/age/*",
        indexes: [
          {
            kind: cosmos.DocumentBase.IndexKind.Range,
            dataType: cosmos.DocumentBase.DataType.String
          },
          {
            kind: cosmos.DocumentBase.IndexKind.Range,
            dataType: cosmos.DocumentBase.DataType.Number
          }
        ]
      },
      {
        path: "/locations/*",
        indexes: [
          {
            kind: cosmos.DocumentBase.IndexKind.Spatial,
            dataType: cosmos.DocumentBase.DataType.Point
          }
        ]
      }
    ]
  });

Добавьте исключенный путь:

containerResponse.body.indexingPolicy.excludedPaths.push({ path: '/name/*' });

Обновите контейнер с изменениями:

const replaceResponse = await client.database('database').container('container').replace(containerResponse.body);

Чтобы мониторить ход выполнения преобразования индекса в контейнере, передайте объект RequestOptions, который устанавливает свойство populateQuotaInfo на true. Получите значение из заголовка x-ms-documentdb-collection-index-transformation-progress ответа.

// retrieve the container's details
const containerResponse = await client.database('database').container('container').read({
    populateQuotaInfo: true
});
// retrieve the index transformation progress from the response headers
const indexTransformationProgress = replaceResponse.headers['x-ms-documentdb-collection-index-transformation-progress'];

Добавьте составной индекс:

 console.log("create container with composite indexes");
  const containerDefWithCompositeIndexes = {
    id: "containerWithCompositeIndexingPolicy",
    indexingPolicy: {
      automatic: true,
      indexingMode: IndexingMode.consistent,
      includedPaths: [
        {
          path: "/*",
        },
      ],
      excludedPaths: [
        {
          path: '/"systemMetadata"/*',
        },
      ],
      compositeIndexes: [
        [
          { path: "/field", order: "ascending" },
          { path: "/key", order: "ascending" },
        ],
      ],
    },
  };
  const containerWithCompositeIndexes = (
    await database.containers.create(containerDefWithCompositeIndexes)
  ).container;

Использование пакета SDK go

Структуру IndexingPolicy определяет политику индексирования для контейнера. Его можно использовать при создании нового контейнера или перенастройке существующего.

db, _ := client.NewDatabase("demodb")

pkDefinition := azcosmos.PartitionKeyDefinition{
	Paths: []string{"/state"},
		Kind:  azcosmos.PartitionKeyKindHash,
}

indexingPolicy := &azcosmos.IndexingPolicy{
	IndexingMode: azcosmos.IndexingModeConsistent,

    // add an included path
	IncludedPaths: []azcosmos.IncludedPath{
		{Path: "/*"},
	},

    // add an excluded path
	ExcludedPaths: []azcosmos.ExcludedPath{
		{Path: "/address/*"},
	},

    // add composite indices
	CompositeIndexes: [][]azcosmos.CompositeIndex{
		{
			{
				Path:  "/name",
				Order: azcosmos.CompositeIndexAscending,
			},
			{
				Path:  "/age",
				Order: azcosmos.CompositeIndexDescending,
			},
		},
	}

	db.CreateContainer(context.Background(), azcosmos.ContainerProperties{
		ID:                     "demo_container",
		PartitionKeyDefinition: pkDefinition,
		IndexingPolicy:         indexingPolicy,
	}, nil)

Использование Python SDK

При использовании пакета SDK для Python версии 3 конфигурация контейнера управляется как словарь. Из этого словаря вы можете получить доступ к политике индексирования и всем его атрибутам. Дополнительные сведения см. в кратком руководстве: Использование Azure Cosmos DB для NoSQL с пакетом SDK Azure для Python.

Получение сведений о контейнере:

containerPath = 'dbs/database/colls/collection'
container = client.ReadContainer(containerPath)

Задайте для режима индексирования согласованность:

container['indexingPolicy']['indexingMode'] = 'consistent'

Определите политику индексирования с включенным путем и пространственным индексом:

container["indexingPolicy"] = {

    "indexingMode":"consistent",
    "spatialIndexes":[
                {"path":"/location/*","types":["Point"]}
             ],
    "includedPaths":[{"path":"/age/*","indexes":[]}],
    "excludedPaths":[{"path":"/*"}]
}

Определите политику индексирования с исключенным путем:

container["indexingPolicy"] = {
    "indexingMode":"consistent",
    "includedPaths":[{"path":"/*","indexes":[]}],
    "excludedPaths":[{"path":"/name/*"}]
}

Добавьте составной индекс:

container['indexingPolicy']['compositeIndexes'] = [
                [
                    {
                        "path": "/name",
                        "order": "ascending"
                    },
                    {
                        "path": "/age",
                        "order": "descending"
                    }
                ]
                ]

Обновите контейнер с изменениями:

response = client.ReplaceContainer(containerPath, container)