簡體   English   中英

如何在給定主分區鍵值列表的情況下一次批量獲取多個項目

[英]How to batch_get_item many items at once given a list of primary partition key values

所以,我有一個 dynamodb 表,其中包含一個主分區鍵列foo_id並且沒有主排序鍵。 我有一個foo_id值列表,並希望獲得與此 id 列表關聯的觀察結果。

我認為最好的方法(?)是使用batch_get_item() ,但它對我不起作用。

    # python code
    import boto3
    client = boto3.client('dynamodb')

    # ppk_values = list of `foo_id` values (strings) (< 100 in this example)
    x = client.batch_get_item(
        RequestItems={
            'my_table_name':
                {'Keys': [{'foo_id': {'SS': [id for id in ppk_values]}}]}
        })

我使用SS是因為我正在傳遞一個字符串列表( foo_id值列表),但我得到:

ClientError: An error occurred (ValidationException) when calling the
BatchGetItem operation: The provided key element does not match the
schema

所以我認為這意味着它認為foo_id包含列表值而不是字符串值,這是錯誤的。

--> 這樣解釋對嗎? 批量查詢一堆主分區鍵值的最佳方法是什么?

應按如下所述給出密鑰。 它不能被稱為“SS”。

基本上,您可以將 DynamoDB 字符串數據類型與字符串(即不與 SS)進行比較。 每個項目都單獨處理。 與 query 中的 SQL 不同

'Keys': [
            {
                'foo_id': key1
            },
            {
                'foo_id': key2
            }
], 

示例代碼:-

您可能需要更改表名和鍵值。

from __future__ import print_function # Python 2/3 compatibility
import boto3
import json
import decimal
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

# Helper class to convert a DynamoDB item to JSON.
class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        return super(DecimalEncoder, self).default(o)

dynamodb = boto3.resource("dynamodb", region_name='us-west-2', endpoint_url="http://localhost:8000")

email1 = "abc@gmail.com"
email2 = "bcd@gmail.com"

try:
    response = dynamodb.batch_get_item(
        RequestItems={
            'users': {
                'Keys': [
                    {
                        'email': email1
                    },
                    {
                        'email': email2
                    },
                ],            
                'ConsistentRead': True            
            }
        },
        ReturnConsumedCapacity='TOTAL'
    )
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    item = response['Responses']
    print("BatchGetItem succeeded:")
    print(json.dumps(item, indent=4, cls=DecimalEncoder))

Boto3 現在有一個batch_get_item版本,它允許您以更自然的 Pythonic 方式傳遞鍵,而無需指定類型。

您可以在https://github.com/awsdocs/aws-doc-sdk-examples 中找到完整且有效的代碼示例。 該示例處理有關重試的一些其他細微差別,但這里是回答此問題的代碼部分的摘要:

import logging
import boto3

dynamodb = boto3.resource('dynamodb')
logger = logging.getLogger(__name__)

movie_table = dynamodb.Table('Movies')
actor_table = dyanmodb.Table('Actors')

batch_keys = {
    movie_table.name: {
        'Keys': [{'year': movie[0], 'title': movie[1]} for movie in movie_list]
    },
    actor_table.name: {
        'Keys': [{'name': actor} for actor in actor_list]
    }
}

response = dynamodb.batch_get_item(RequestItems=batch_keys)

for response_table, response_items in response.items():
    logger.info("Got %s items from %s.", len(response_items), response_table)

批准的答案不再有效。

對我來說,工作呼叫格式是這樣的:

import boto3
client = boto3.client('dynamodb')

# ppk_values = list of `foo_id` values (strings) (< 100 in this example)
x = client.batch_get_item(
    RequestItems={
        'my_table_name': {
            'Keys': [{'foo_id': {'S': id}} for id in ppk_values]
        }
    }
)

要求類型的信息。 對我來說,字符串鍵是“S”。 沒有它,我得到一個錯誤,說庫找到了一個str但期望一個dict 也就是說,他們想要{'foo_id': {'S': id}}而不是我首先嘗試的更簡單的{'foo_id': id}

這是 dynamodb 版本 2.15.0 的 java 解決方案。 假設 foo_id 是字符串類型並且鍵小於 100。您可以將列表分成所需大小的批次

private void queryTable(List<String> keys){

    List<Map<String, AttributeValue>> keysBatch = keys.stream()
            .map(key -> singletonMap("foo_id", AttributeValue.builder().s(key).build()))
            .collect(toList());
    KeysAndAttributes keysAndAttributes = KeysAndAttributes.builder()
            .keys(keysBatch)
            .build();
    Map<String, KeysAndAttributes> requestItems = new HashMap<>();
    requestItems.put("tableName", keysAndAttributes);
    BatchGetItemRequest batchGet = BatchGetItemRequest.builder()
            .requestItems(requestItems)
            .build();
    Map<String, List<Map<String, AttributeValue>>> responses = dbClient.batchGetItem(batchGet).responses();
    responses.entrySet().stream().forEach(entry -> {
        System.out.println("Table : " + entry.getKey());
        entry.getValue().forEach(v -> {
            System.out.println("value: "+v);
        });
    });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM