Как запросить массив значений первичного ключа в DynamodB

У меня есть одна таблица в AWS Dynamodb с 1 миллионом записей. Можно ли запросить массив значений первичного ключа в одном запросе с дополнительным условием ключа сортировки в Dynamodb? Я использую для своей серверной логики.

Вот парамс

var params = {
TableName: "client_logs",
KeyConditionExpression: "#accToken = :value AND ts between :val1 and 
:val2", 
ExpressionAttributeNames: {
"#accToken": "acc_token"
},
ExpressionAttributeValues: {
        ":value": clientAccessToken,
        ":val1": parseInt(fromDate),
        ":val2": parseInt(toDate),
        ":status":confirmStatus
},
FilterExpression:"apiAction = :status"


};

Здесь acc_token является первичным ключом, и я хочу запросить массив значений access_token в одном запросе.

2 ответа

Нет, это невозможно. Один запрос может искать только одно конкретное значение хеш-ключа. (См. DynamoDB - Запрос.)

Однако вы можете выполнять несколько запросов параллельно, что даст желаемый эффект.

Изменить (2018-11-21)

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

Я не знаю, как распределяются ваши данные, поэтому я не могу сказать, какой из них лучше для вас. Во всех случаях мы не можем использовать acc_token в качестве ключа сортировки GSI, потому что вы не можете использовать IN оператор в выражении KeyConditionExpression. (См. DynamoDB - Условие.)

Решение 1

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

шаги:

  1. Добавьте новый атрибут к элементам, которые вы записываете в свою таблицу. Этот новый атрибут может быть числом или строкой. Давайте назовем это index_partition,
  2. Когда вы записываете новый элемент в вашу таблицу, присвойте ему случайное значение из 0 в N за index_partition, (Вот, N некоторая произвольная константа по вашему выбору. 9 это, вероятно, нормальное значение для начала.)
  3. Создать GSI с хеш-ключом index_partition и ключ сортировки ts, Вам нужно будет спроектировать apiAction а также acc_token в GSI.
  4. Теперь вам нужно только выполнить N запросы. Используйте ключевое условие выражения index_partition = :n AND ts between :val1 and :val2 и выражение фильтра apiAction = :status AND acc_token in :acc_token_list

Решение 2

Это решение аналогично последнему, но вместо случайного шардинга GSI мы будем использовать раздел GSI на основе даты.

шаги:

  1. Добавьте новый строковый атрибут к элементам, которые вы записываете в свою таблицу. Давайте назовем это ts_ymd,
  2. Когда вы пишете новый элемент в вашу таблицу, используйте только yyyy-mm-dd часть ts установить значение ts_ymd, (Вы можете использовать любую гранулярность, которая вам нравится. Это зависит от вашего типичного диапазона запросов для ts, Если :val1 а также :val2 обычно находятся всего в часе друг от друга, тогда подходящим ключом раздела GSI может быть гггг-мм-дд-чч.)
  3. Создать GSI с хеш-ключом ts_ymd и ключ сортировки ts, Вам нужно будет спроектировать apiAction а также acc_token в GSI.
  4. Предполагая, что вы использовали yyyy-mm-dd для ключа раздела GSI, вам нужно выполнять только один запрос на каждый день, который находится в пределах :val1 а также :val2, Используйте ключевое условие выражения ts_ymd = :ymd AND ts between :val1 and :val2 и выражение фильтра apiAction = :status AND acc_token in :acc_token_list

Решение 3

Я не знаю, сколько разных значений apiAction Есть и как эти значения распределяются, но если их несколько, и они имеют примерно одинаковое распределение, вы можете разделить GSI на основе этого значения. Чем больше возможных значений у вас есть для apiActionЧем лучше это решение для вас. Ограничивающим фактором здесь является то, что вам нужно иметь достаточно значений, чтобы вы не столкнулись с пределом в 10 ГБ для вашего GSI.

шаги:

  1. Создать GSI с хеш-ключом apiAction и ключ сортировки ts, Вам нужно будет спроектировать acc_token в GSI.
  2. Вам нужно выполнить только один запрос. Используйте ключевое условие выражения apiAction = :status AND ts between :val1 and :val2" and a filter expression ofacc_token in: acc_token_list`.

Для всех этих решений следует учитывать, насколько равномерно будет распределяться ключ раздела GSI, и размер типичного диапазона для ts в вашем запросе. Вы должны использовать выражение фильтра на acc_token, поэтому вы должны попытаться выбрать решение, которое минимизирует общее количество элементов, которые будут соответствовать вашему выражению условия ключа, но в то же время вы должны знать, что для одного ключа раздела не может быть более 10 ГБ данных (для таблицы или для GSI). Вы также должны помнить, что GSI может быть запрошен только как окончательно согласованное чтение.

Вы можете эффективно выполнять как запрос диапазона ключей раздела, так и применять дополнительное условие к ключу сортировки с помощью запроса PartiQL SELECT . Официальная документация DDB гласит:

Чтобы гарантировать, что инструкция SELECT не приведет к полному сканированию таблицы, условие предложения WHERE должно указывать ключ секции. Используйте оператор равенства или IN.

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

Таким образом, ваш запрос может выглядеть так:

      SELECT * FROM client_logs WHERE acc_token IN (t1, t2, ...) AND ts BETWEEN t1 AND t2

Примеры Node.js использования PartiQL API можно найти здесь .

Другие вопросы по тегам