Странное поведение с begin_with и двоичным столбцом в DynamoDB - PullRequest
0 голосов
/ 03 мая 2020

Сводка

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

Подробности

У меня есть таблица DynamoDB со следующей схемой:

user_id - Primary Key - binary - Contains 16 byte UUID
project_id_item_id - Sort Key - binary - 32 bytes - two UUIDs concatinated

Во время выполнения моих модульных тестов локально с использованием dynamodb-local docker image Я наблюдал странное поведение

Я вставил 20 элементов в свою таблицу например:

table.put_item(
    Item={
        'user_id': user_id.bytes,
        'project_id_item_id': project_id.bytes + item_id.bytes
    }
)              

Каждый элемент имеет одинаковые user_id и одинаковые project_id с разными item_id.

Когда я пытаюсь запросить те же данные обратно, иногда (возможно, 1 из 5 раз, когда я запускаю тест), я получаю только некоторые элементы обратно:

table.query(
    KeyConditionExpression=
        Key('user_id').eq(user_id.bytes) &
        Key('project_id_item_id').begins_with(project_id.bytes))
)
# Only returns 14 items

Если я отбрасываю 2-е условие из выражения KeyConditionExpression, я получаю все 20 элементов.

Если я запускаю сканирование вместо запроса и использую одно и то же выражение условия, я получаю все 20 элементов

table.scan(
    FilterExpression=
        Key('user_id').eq(user_id.bytes) &
        Key('project_id_item_id').begins_with(project_id.bytes))
)
# 20 items are returned

Если я печатаю project_id_item_id для каждого элемента в таблице, я вижу, что все они начинаются с одного и того же project_id:

[i['project_id_item_id'].value.hex() for i in table.scan()['Items']]

# Result:
  |---------Project Id-----------|
['76761923aeba4edf9fccb9eeb5f80cc40604481b26c84c73b63308dd588a4df1',
 '76761923aeba4edf9fccb9eeb5f80cc40ec926452c294c909befa772b86e2175',
 '76761923aeba4edf9fccb9eeb5f80cc460ff943b36ec44518175525d6eb30480',
 '76761923aeba4edf9fccb9eeb5f80cc464e427afe84d49a5b3f890f9d25ee73b',
 '76761923aeba4edf9fccb9eeb5f80cc466f3bfd77b14479a8977d91af1a5fa01',
 '76761923aeba4edf9fccb9eeb5f80cc46cd5b7dec9514714918449f8b49cbe4e',
 '76761923aeba4edf9fccb9eeb5f80cc47d89f44aae584c1c9da475392cb0a085',
 '76761923aeba4edf9fccb9eeb5f80cc495f85af4d1f142608fae72e23f54cbfb',
 '76761923aeba4edf9fccb9eeb5f80cc496374432375a498b937dec3177d95c1a',
 '76761923aeba4edf9fccb9eeb5f80cc49eba93584f964d13b09fdd7866a5e382',
 '76761923aeba4edf9fccb9eeb5f80cc4a6086f1362224115b7376bc5a5ce66b8',
 '76761923aeba4edf9fccb9eeb5f80cc4b5c6872aa1a84994b6f694666288b446',
 '76761923aeba4edf9fccb9eeb5f80cc4be07cd547d804be4973041cfd1529734',
 '76761923aeba4edf9fccb9eeb5f80cc4c48daab011c449f993f061da3746a660',
 '76761923aeba4edf9fccb9eeb5f80cc4d09bc44973654f39b95a91eb3e291c68',
 '76761923aeba4edf9fccb9eeb5f80cc4d0edda3d8c6643ad8e93afe2f1b518d4',
 '76761923aeba4edf9fccb9eeb5f80cc4d8d1f6f4a85e47d78e2d06ec1938ee2a',
 '76761923aeba4edf9fccb9eeb5f80cc4dc7323adfa35423fba15f77facb9a41b',
 '76761923aeba4edf9fccb9eeb5f80cc4f948fb40873b425aa644f220cdcb5d4b',
 '76761923aeba4edf9fccb9eeb5f80cc4fc7f0583f593454d92a8a266a93c6fcd']

В качестве проверки работоспособности, вот Project_id, который я использую в своем запросе:

print(project_id)
76761923-aeba-4edf-9fcc-b9eeb5f80cc4  # Matches what's returned by scan above

Наконец, самая странная часть - я могу попытаться сопоставить меньшее количество байтов идентификатора проекта и Я начинаю видеть все 20 предметов, затем ноль предметов, затем снова все 20 предметов:

hash_key = Key('hash_key').eq(hash_key)
for n in range(1,17):
    short_key = project_id.bytes[:n]
    range_key = Key('project_id_item_id').begins_with(short_key)
    count = table.query(KeyConditionExpression=hash_key & range_key)['Count']
    print("If I only query for 0x{:32} I find {} items".format(short_key.hex(), count))

Получаю меня:

If I only query for 0x76                               I find 20 items
If I only query for 0x7676                             I find 20 items
If I only query for 0x767619                           I find 20 items
If I only query for 0x76761923                         I find 20 items
If I only query for 0x76761923ae                       I find 20 items
If I only query for 0x76761923aeba                     I find 20 items
If I only query for 0x76761923aeba4e                   I find 20 items
If I only query for 0x76761923aeba4edf                 I find 0 items
If I only query for 0x76761923aeba4edf9f               I find 20 items
If I only query for 0x76761923aeba4edf9fcc             I find 0 items
If I only query for 0x76761923aeba4edf9fccb9           I find 20 items
If I only query for 0x76761923aeba4edf9fccb9ee         I find 0 items
If I only query for 0x76761923aeba4edf9fccb9eeb5       I find 20 items
If I only query for 0x76761923aeba4edf9fccb9eeb5f8     I find 20 items
If I only query for 0x76761923aeba4edf9fccb9eeb5f80c   I find 20 items
If I only query for 0x76761923aeba4edf9fccb9eeb5f80cc4 I find 15 items

Я совершенно ошеломлен этим паттерном. Если ключ диапазона, который я ищу, имеет длину 8, 10 или 12 байт, я не получаю совпадений. Если его длина составляет 16 байт, я получаю меньше 20, но больше 0 совпадений.

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

Похоже, это может быть связано с UUID project_id , Если в тесте я жестко закодирую его на 76761923-aeba-4edf-9fcc-b9eeb5f80cc4, я могу заставить его пропускать каждый раз.

1 Ответ

0 голосов
/ 03 мая 2020

Это может быть шестилетняя ошибка в локальном DynamoDB Я оставлю этот вопрос открытым, если у кого-то будет больше проницательности, и я обновлю этот ответ, если смогу узнать больше информации от Amazon.

...