Учебники

DynamoDB — Глобальные вторичные индексы

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

Например — Система, отслеживающая пользователей, их статус входа в систему и время их входа в систему. Рост предыдущего примера замедляет запросы к своим данным.

Глобальные вторичные индексы ускоряют запросы, организуя выбор атрибутов из таблицы. Они используют первичные ключи при сортировке данных и не требуют атрибутов таблицы ключей или схемы ключей, идентичной таблице.

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

В проекции можно использовать другие атрибуты таблицы, однако запросы не извлекаются из родительских таблиц.

Прогнозы атрибутов

Проекции состоят из набора атрибутов, скопированных из таблицы во вторичный индекс. Проекция всегда происходит с ключом разделения таблицы и ключом сортировки. В запросах проекции предоставляют DynamoDB доступ к любому атрибуту проекции; они по существу существуют как их собственная таблица.

При создании вторичного индекса необходимо указать атрибуты для проекции. DynamoDB предлагает три способа выполнить эту задачу —

  • KEYS_ONLY — Все элементы индекса состоят из значений разделов таблицы и ключей сортировки, а также значений ключей индекса. Это создает наименьший индекс.

  • INCLUDE — включает атрибуты KEYS_ONLY и неключевые атрибуты.

  • ALL — включает все атрибуты исходной таблицы, создавая максимально возможный индекс.

KEYS_ONLY — Все элементы индекса состоят из значений разделов таблицы и ключей сортировки, а также значений ключей индекса. Это создает наименьший индекс.

INCLUDE — включает атрибуты KEYS_ONLY и неключевые атрибуты.

ALL — включает все атрибуты исходной таблицы, создавая максимально возможный индекс.

Обратите внимание на компромиссы при проецировании атрибутов в глобальный вторичный индекс, которые относятся к пропускной способности и стоимости хранения.

Рассмотрим следующие моменты —

  • Если вам нужен только доступ к нескольким атрибутам с низкой задержкой, проецируйте только те, которые вам нужны. Это уменьшает затраты на хранение и запись.

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

  • Вы можете проецировать большие наборы часто используемых атрибутов, однако это приводит к высокой стоимости хранения.

  • Используйте KEYS_ONLY для нечастых запросов к таблицам и частых записей / обновлений. Это контролирует размер, но все же предлагает хорошую производительность по запросам.

Если вам нужен только доступ к нескольким атрибутам с низкой задержкой, проецируйте только те, которые вам нужны. Это уменьшает затраты на хранение и запись.

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

Вы можете проецировать большие наборы часто используемых атрибутов, однако это приводит к высокой стоимости хранения.

Используйте KEYS_ONLY для нечастых запросов к таблицам и частых записей / обновлений. Это контролирует размер, но все же предлагает хорошую производительность по запросам.

Глобальный вторичный индекс Запросы и сканирование

Вы можете использовать запросы для доступа к одному или нескольким элементам в индексе. Вы должны указать индекс и имя таблицы, желаемые атрибуты и условия; с возможностью возврата результатов в порядке возрастания или убывания.

Вы также можете использовать сканы, чтобы получить все данные индекса. Требуется имя таблицы и индекса. Вы используете выражение фильтра для извлечения определенных данных.

Синхронизация данных таблиц и индексов

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

Вам необходимо понять влияние обслуживания DynamoDB на индексы. При создании индекса вы указываете ключевые атрибуты и типы данных, что означает, что при записи эти типы данных должны соответствовать типам данных схемы ключей.

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

Вопросы пропускной способности в глобальных вторичных индексах — Несколько глобальных вторичных индексов влияют на пропускную способность. Для создания индекса требуются спецификации единиц емкости, которые существуют отдельно от таблицы, что приводит к тому, что операции потребляют единицы емкости индекса, а не единицы таблицы.

Это может привести к регулированию, если запрос или запись превышает выделенную пропускную способность. Просмотр настроек пропускной способности с помощью DescribeTable .

Емкость чтения — глобальные вторичные индексы обеспечивают возможную согласованность. В запросах DynamoDB выполняет расчеты обеспечения, идентичные тем, которые используются для таблиц, с единственной разницей в использовании размера элемента индекса, а не размера элемента. Предел возвращаемых запросов остается 1 МБ, который включает размер имени атрибута и значения для каждого возвращаемого элемента.

Емкость записи

Когда происходят операции записи, затронутый индекс потребляет единицы записи. Расходы на пропускную способность записи представляют собой сумму единиц емкости записи, потребляемых при записи в таблицу, и единиц, используемых в обновлениях индекса. Успешная операция записи требует достаточной емкости или приводит к дросселированию.

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

  • Новые элементы, определяющие индексированные атрибуты, или обновления элементов, определяющие неопределенные индексированные атрибуты, используют одну операцию записи для добавления элемента в индекс.

  • Обновления, изменяющие значение атрибута индексированного ключа, используют две записи для удаления элемента и записи нового.

  • Запись таблицы, инициирующая удаление индексированного атрибута, использует одну запись, чтобы стереть проекцию старого элемента в индексе.

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

  • Обновления, изменяющие только значение прогнозируемого атрибута в схеме ключа индекса, а не значение атрибута индексированного ключа, используют одну запись для обновления значений прогнозируемых атрибутов в индексе.

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

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

Запись таблицы, инициирующая удаление индексированного атрибута, использует одну запись, чтобы стереть проекцию старого элемента в индексе.

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

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

Все эти факторы предполагают, что размер элемента не превышает 1 КБ.

Глобальное вторичное хранилище индексов

При записи элемента DynamoDB автоматически копирует правильный набор атрибутов в любые индексы, где атрибуты должны существовать. Это влияет на вашу учетную запись, взимая плату за хранение элементов таблицы и атрибутов. Используемое пространство получается из суммы этих величин:

  • Размер байта первичного ключа таблицы
  • Размер в байтах атрибута индекса ключа
  • Размер в байтах проектируемых атрибутов
  • 100 байтов на каждый элемент индекса

Вы можете оценить потребности в хранилище путем оценки среднего размера элемента и умножения на количество элементов таблицы с атрибутами ключа глобального вторичного индекса.

DynamoDB не записывает данные элемента для элемента таблицы с неопределенным атрибутом, определенным как раздел индекса или ключ сортировки.

Глобальный вторичный индекс Crud

Создайте таблицу с глобальными вторичными индексами, используя операцию CreateTable в паре с параметром GlobalSecondaryIndexes . Вы должны указать атрибут, который будет служить ключом индекса, или использовать другой для ключа сортировки индекса. Все атрибуты ключа индекса должны быть строковыми, числовыми или двоичными скалярами. Также необходимо указать параметры пропускной способности, состоящие из ReadCapacityUnits и WriteCapacityUnits .

Используйте UpdateTable, чтобы еще раз добавить глобальные вторичные индексы к существующим таблицам, используя параметр GlobalSecondaryIndexes.

В этой операции вы должны предоставить следующие входные данные —

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

При добавлении глобального вторичного индекса для больших таблиц может потребоваться значительное время из-за объема элемента, объема прогнозируемых атрибутов, емкости записи и активности записи. Используйте метрики CloudWatch для мониторинга процесса.

Используйте DescribeTable для получения информации о состоянии для глобального вторичного индекса. Возвращает один из четырех IndexStatus для GlobalSecondaryIndexes —

  • СОЗДАНИЕ — указывает этап построения индекса и его недоступность.

  • ACTIVE — указывает на готовность индекса к использованию.

  • ОБНОВЛЕНИЕ — показывает состояние обновления настроек пропускной способности.

  • УДАЛЕНИЕ — указывает на состояние удаления индекса и его постоянную недоступность для использования.

СОЗДАНИЕ — указывает этап построения индекса и его недоступность.

ACTIVE — указывает на готовность индекса к использованию.

ОБНОВЛЕНИЕ — показывает состояние обновления настроек пропускной способности.

УДАЛЕНИЕ — указывает на состояние удаления индекса и его постоянную недоступность для использования.

Обновите настройки пропускной способности глобального вторичного индекса на стадии загрузки / обратной засыпки (атрибуты записи DynamoDB в индекс и отслеживание добавленных / удаленных / обновленных элементов). Используйте UpdateTable для выполнения этой операции.

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

Используйте UpdateTable для удаления глобальных вторичных индексов. Это позволяет удалять только один индекс на одну операцию, однако вы можете выполнять несколько операций одновременно, до пяти. Процесс удаления не влияет на операции чтения / записи родительской таблицы, но вы не можете добавлять / удалять другие индексы, пока операция не завершится.

Использование Java для работы с глобальными вторичными индексами

Создайте таблицу с индексом через CreateTable. Просто создайте экземпляр класса DynamoDB, экземпляр класса CreateTableRequest для запроса информации и передайте объект запроса в метод CreateTable.

Следующая программа является кратким примером —

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
// Attributes 
ArrayList<AttributeDefinition> attributeDefinitions = new 
   ArrayList<AttributeDefinition>();  
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("City") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Date") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Wind") 
   .withAttributeType("N"));
   
// Key schema of the table 
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>(); 
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("City") 
   .withKeyType(KeyType.HASH));              //Partition key
   
tableKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
// Wind index 
GlobalSecondaryIndex windIndex = new GlobalSecondaryIndex() 
   .withIndexName("WindIndex") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 10) 
   .withWriteCapacityUnits((long) 1)) 
   .withProjection(new Projection().withProjectionType(ProjectionType.ALL));
   
ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>(); 
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.HASH));              //Partition key
   
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Wind") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
windIndex.setKeySchema(indexKeySchema);  
CreateTableRequest createTableRequest = new CreateTableRequest() 
   .withTableName("ClimateInfo") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 5) 
   .withWriteCapacityUnits((long) 1))
   .withAttributeDefinitions(attributeDefinitions) 
   .withKeySchema(tableKeySchema) 
   .withGlobalSecondaryIndexes(windIndex); 
Table table = dynamoDB.createTable(createTableRequest); 
System.out.println(table.getDescription());

Получить информацию индекса с DescribeTable . Сначала создайте экземпляр класса DynamoDB. Затем создайте экземпляр класса Table для целевого индекса. Наконец, передайте таблицу методу описания.

Вот короткий пример —

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
TableDescription tableDesc = table.describe();  
Iterator<GlobalSecondaryIndexDescription> gsiIter = 
   tableDesc.getGlobalSecondaryIndexes().iterator(); 

while (gsiIter.hasNext()) { 
   GlobalSecondaryIndexDescription gsiDesc = gsiIter.next(); 
   System.out.println("Index data " + gsiDesc.getIndexName() + ":");  
   Iterator<KeySchemaElement> kse7Iter = gsiDesc.getKeySchema().iterator(); 
   
   while (kseIter.hasNext()) { 
      KeySchemaElement kse = kseIter.next(); 
      System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType()); 
   }
   Projection projection = gsiDesc.getProjection(); 
   System.out.println("\tProjection type: " + projection.getProjectionType()); 
   
   if (projection.getProjectionType().toString().equals("INCLUDE")) { 
      System.out.println("\t\tNon-key projected attributes: " 
         + projection.getNonKeyAttributes()); 
   } 
}

Используйте Query для выполнения запроса индекса, как с запросом таблицы. Просто создайте экземпляр класса DynamoDB, экземпляр класса Table для целевого индекса, экземпляр класса Index для определенного индекса и передайте объект индекса и запроса в метод запроса.

Взгляните на следующий код, чтобы лучше понять —

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
Index index = table.getIndex("WindIndex");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("#d = :v_date and Wind = :v_wind") 
   .withNameMap(new NameMap() 
   .with("#d", "Date"))
   .withValueMap(new ValueMap() 
   .withString(":v_date","2016-05-15") 
   .withNumber(":v_wind",0));
   
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator();

while (iter.hasNext()) {
   System.out.println(iter.next().toJSONPretty()); 
}

Следующая программа является большим примером для лучшего понимания —

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

В этом примере также используются Eclipse IDE, файл учетных данных AWS и набор инструментов AWS в Java-проекте Eclipse AWS.