2013-02-12 3 views
57

Идет из реляционных справочной базы данных и пытаюсь работать с Амазонка DynamoDBЗапросы DynamoDB по дате

У меня есть таблица с хэш-ключом «DataID» и рядом «CreatedAt» и кучей предметов в Это.

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

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

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

ответ

26

Обновлено Ответ:

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

Для использования в этом вопросе вы хотели бы использовать глобальный вторичный индекс в поле «Создано».

Более подробную информацию о DynamoDB вторичных индексов see the secondary index documentation

Оригинал Ответ:

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

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

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

+8

См. Комментарии к нижеприведенному ответу; есть * не * способы справиться с этим сейчас, по крайней мере, не для того, что спросил ОП. В GSI по-прежнему требуется указать хэш-ключ, поэтому вы не можете запрашивать все записи с 'CreatedAt' больше определенной точки. – pkaeding

+0

@pkaeding Чтобы выполнить проверку против GSI, вы должны указать значение хэша, это правильно. Хотя это значение хеша для GSI (ключевое поле) НЕ Хэш-значение для базовой таблицы. API сканирования позволяет использовать '>' условия фильтрации, которые необходимы для этого варианта использования. –

+0

@MikeBrant правильно, но вопрос задал вопрос о том, как «получить ** все» элементы, созданные после определенной даты и отсортированные по дате »(акцент мой). Насколько мне известно, это невозможно. – pkaeding

3

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

1

У вас может быть несколько одинаковых хэш-ключей; но только если у вас есть ключ диапазона, который меняется. Думайте об этом как о форматах файлов; вы можете иметь 2 файла с тем же именем в одной папке, если их формат отличается. Если их формат совпадает, их имя должно быть другим. Такая же концепция применяется к клавишам хэша/диапазона DynamoDB; просто подумайте о хеше, как о названии и диапазоне, как о формате.

Кроме того, я не помню, имели ли они их во время OP (я не верю, что они это сделали), но теперь они предлагают локальные вторичные индексы.

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

Я по-прежнему рекомендую ответ Майка Бранта как предпочтительный метод использования DynamoDB; и использовать этот метод самостоятельно. В моем случае у меня просто есть центральная таблица с только хэш-ключом в качестве моего идентификатора, а затем вторичные таблицы, которые имеют хэш и диапазон, которые могут быть запрошены, тогда элемент указывает код на «интересующий элемент» центральной таблицы, непосредственно ,

Дополнительные данные относительно вторичных индексов можно найти в документации Амазонки DynamoDB here для заинтересованных лиц.

В любом случае, надеюсь, это поможет кому-то еще, что происходит по этой теме.

+0

Я попытался создать таблицу DynamoDB, где был AWSDynamoDBKeySchemaElement 'createdAt' типа хеш и снова AWSDynamoDBKeySchemaElement 'createdAt' типа, и я получил сообщение об ошибке Error Domain = com.amazonaws.AWSDynamoDBErrorDomain Code = 0 "(null)" UserInfo = {__ type = com.amazon.coral.validate # ValidationException, message = Оба ключа Hash и элемент Range Key в KeySchema имеют одинаковое имя}. Поэтому я не думаю, что вы говорите правильно. – user1709076

+0

Я считаю, что вы неправильно поняли (хотя я полагаю, что и в моем описании я был не очень ясен). Вы не можете иметь 2 разных атрибута (столбцы) с тем же именем в таблице, но при создании хэш-ключа с ключом диапазона вы можете иметь несколько элементов, которые используют один и тот же хэш, если их диапазон отличается, и наоборот. Например: ваш хэш - это «ID», а ваш диапазон «Дата», у вас может быть 2 экземпляра идентификатора «1234», если их дата отличается. – DGolberg

+0

Ah DGoldberg! Я вас поймаю. Замечательно. Поэтому для моего случая, поскольку я только и всегда просто хочу запросить текстовые сообщения «после даты = x», похоже, я мог установить, что все текстовые сообщения имеют одинаковые «fake_hash = 1». Затем сделайте запрос query.keyConditionExpression = @ "fake_hash = 1 и #Date>: val". Большое спасибо. Если у вас есть какой-либо другой ввод, я был бы рад услышать его, так как кажется странным иметь хеш, который всегда имеет одно и то же значение? – user1709076

-7

Вы можете сделать это сейчас в DynamoDB с помощью GSI. Создайте поле «CreatedAt» как GSI и задайте такие запросы, как (GT some_date). Сохраните дату в виде числа (msecs с эпохи) для таких запросов.

Подробная информация доступна здесь: Глобальные вторичные индексы - Amazon DynamoDB: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using

Это очень мощная функция. Имейте в виду, что запрос ограничен (EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN) Состояние - Amazon DynamoDB: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html

+29

Я отказался, потому что, насколько я могу судить, ваш ответ неверен. Как первичный ключ таблицы, вы можете запросить хэш-ключ GSI только с помощью оператора EQ. Если вы подразумевали, что «CreatedAt» должен быть ключом диапазона GSI, тогда вам нужно выбрать хэш-ключ, а затем вы вернетесь туда, где вы начали, потому что вы сможете запросить GT только на «CreatedAt» для определенного значения хэш-ключа. – PaF

+0

Согласовано с PaF. Использование GSI с хэш-ключом, поскольку время создания не помогает с вопросом, заданным в OP. –

4

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

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

| ID | DataID | Created | Data | 
|------+--------+---------+------| 
| hash | xxxxx | 1234567 | blah | 

Ваш Hash Ключ ID Ваш вторичный индекс определяется как: DataID-Созданный индекс (это имя, которое DynamoDB будет использовать)

Затем вы можете сделать запрос следующим образом:

var params = { 
    TableName: "Table", 
    IndexName: "DataID-Created-index", 
    KeyConditionExpression: "DataID = :v_ID AND Created > :v_created", 
    ExpressionAttributeValues: {":v_ID": {S: "some_id"}, 
           ":v_created": {N: "timestamp"} 
    }, 
    ProjectionExpression: "ID, DataID, Created, Data" 
}; 

ddb.query(params, function(err, data) { 
    if (err) 
     console.log(err); 
    else { 
     data.Items.sort(function(a, b) { 
      return parseFloat(a.Created.N) - parseFloat(b.Created.N); 
     }); 
     // More code here 
    } 
}); 

По существу ваш запрос выглядит следующим образом:

SELECT * FROM TABLE WHERE DataID = "some_id" AND Created > timestamp; 

secondar y Индекс увеличит требуемые единицы чтения/записи, поэтому вам необходимо это учитывать. Это все же намного лучше, чем делать сканирование, которое будет дорогостоящим в чтении и вовремя (и ограничено 100 пунктами, которые я считаю).

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

+1

Вы говорите, что ограничений нет, но вы должны знать, что этот подход означает, что вы можете сохранить не более 10 ГБ данных (максимум одного раздела). –

5

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

Hash Key     | Range Key 
------------------------------------ 
Date value of CreatedAt | CreatedAt 

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

Таким образом, я всегда могу указать HashKey как день текущей даты, а RangeKey может использовать> и < операторы во время извлечения. Таким образом, данные также распространяются на несколько осколков.

13

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

Запросы могут быть выполнены только в одном разделе. Это действительно конец истории. Это означает, что если вы хотите запросить дату (вы хотите использовать msec с эпохи), тогда все элементы, которые вы хотите получить в одном запросе, должны иметь один и тот же Hash (раздел).

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

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

Самое лучшее, что нужно сделать, это определить более полезные разделы, чтобы создать для сохранения данных:

  • вам действительно нужно смотреть на все строки, или это только те строки, определенным пользователем ли?

  • Было бы хорошо сначала сузить список по месяцам и выполнить несколько запросов (по одному на каждый месяц)? Или Годом?

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

+0

Я хочу подчеркнуть вариант, который вы изложили в своем последнем абзаце о рассмотрении «по годам». Создайте для этого атрибут, например 'yyyy' и хеш, но также создайте дату' created', которую вы можете использовать в качестве ключа диапазона. Затем вы получаете 10 ГБ данных в год (27 МБ в день), что, вероятно, отлично подходит для большего количества обстоятельств. Это означает, что вы должны создать запрос в год, когда запросы на даты пройдут через границу года, но, по крайней мере, это сработает, и это безопаснее, чем создание фиктивного хэш-ключа. –

+0

Другой вариант: http://stackoverflow.com/questions/35963243/how-to-query-dynamodb-by-date-range-key-with-no-obvious-hash-key?noredirect11&lq=1 –

+0

как ссылка выше объясняет, что строго временные ключи разделов могут привести к горячим точкам. если вы должны использовать временные ключи разделов, лучше добавить другой элемент в ключ раздела, чтобы разложить период времени на несколько разделов. Я видел предложения просто использовать префикс между 0-n, где n - количество разделов, каждый раз, когда ведро должно быть распространено. – dres