DynamoDB BatchWriteItem:提供的项目键列表包含重复项

问题描述 投票:0回答:3

我正在尝试使用DynamoDB操作

BatchWriteItem
,其中我想将多条记录插入到一个表中。

该表有 1 个分区键和 1 个排序键。

我正在使用 AWS lambda 和 Go 语言。

我将元素插入到切片中。

我正在遵循此程序。

  1. 创建

    PutRequest
    结构并为列表中的第一条记录添加 AttributeValues。

  2. 我正在由此创建

    WriteRequest
    PutRequest

  3. 我正在将此

    WriteRequest
    添加到
    array of WriteRequests

  4. 我正在创建

    BatchWriteItemInput
    ,它由
    RequestItems
    组成,它基本上是一个 Tablename 的映射和
    WriteRequests
    的数组。

之后我调用

BatchWriteItem
,这会导致错误:

Provided list of item keys contains duplicates.

任何指示,为什么会发生这种情况?

amazon-web-services aws-lambda amazon-dynamodb
3个回答
25
投票

您提供了两个或多个具有相同主键的项目(在您的情况下意味着相同的分区和排序键)。

根据 BatchWriteItem 文档,您不能在同一 BatchWriteItem 请求中对同一项目执行多个操作。


3
投票

注意事项:这个答案适用于Python

正如 @Benoit 所说,boto3 文档指出:

如果您想绕过单批写入请求的重复限制,如 botocore.exceptions.ClientError: 调用 BatchWriteItem 操作时发生错误 (ValidationException): 提供的项键列表包含重复项。

您可以根据

文档
源代码在批处理编写器上指定overwrite_by_pkeys=['partition_key', 'sort_key']“如果与指定主键上的新请求项匹配,则删除缓冲区中的重复请求项”。也就是说,如果缓冲区中已存在主排序组合,它将删除该请求并用新请求替换它

示例

假设您想要将 pandas 数据帧写入 DynamoDB 表,以下函数可能会有所帮助,

import json 
import datetime as dt 
import boto3 
import pandas as pd 
from typing import Optional

def write_dynamoDB(df:'pandas.core.frame.DataFrame', tbl:str, partition_key:Optional[str]=None, sort_key:Optional[str]=None):
    '''
       Function to write a pandas DataFrame to a DynamoDB Table through 
       batchWrite operation. In case there are any float values it handles 
       them by converting the data to a json format.  
       Arguments: 
       * df: pandas DataFrame to write to DynamoDB table. 
       * tbl: DynamoDB table name. 
       * partition_key (Optional): DynamoDB table partition key. 
       * sort_key (Optional): DynamoDB table sort key. 
    '''

    # Initialize AWS Resource 
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(tbl)

    # Check if overwrite keys were provided
    overwrite_keys = [partition_key, sort_key] if partition_key else None

    # Check if they are floats (convert to decimals instead) 
    if any([True for v in df.dtypes.values if v=='float64']):

        from decimal import Decimal

        # Save decimals with JSON
        df_json = json.loads(
                       json.dumps(df.to_dict(orient='records'),
                                  default=date_converter,
                                  allow_nan=True), 
                       parse_float=Decimal
                       )

        # Batch write 
        with table.batch_writer(overwrite_by_pkeys=overwrite_keys) as batch: 
            for element in df_json:
                batch.put_item(
                Item=element
            )

    else: # If there are no floats on data 

    # Batch writing 
        with table.batch_writer(overwrite_by_pkeys=overwrite_keys) as batch: 

            columns = df.columns

            for row in df.itertuples():
                batch.put_item(
                    Item={
                        col:row[idx+1] for idx,col in enumerate(columns)
                    }
                )

def date_converter(obj):
    if isinstance(obj, dt.datetime):
        return obj.__str__()
    elif isinstance(obj, dt.date):
        return obj.isoformat()

致电

write_dynamoDB(dataframe, 'my_table', 'the_partition_key', 'the_sort_key')


2
投票

使用

batch_writer
代替
batch_write_item
:

import boto3

dynamodb = boto3.resource("dynamodb", region_name='eu-west-1')
my_table = dynamodb.Table('mirrorfm_yt_tracks')

with my_table.batch_writer(overwrite_by_pkeys=["user_id", "game_id"]) as batch:
    for item in items:
        batch.put_item(
            Item={
                'user_id': item['user_id'],
                'game_id': item['game_id'],
                'score': item['score']
            }
        )

如果您没有排序键,

overwrite_by_pkeys
可以是
None

这基本上与@MiguelTrejo 相同的答案(谢谢!+1),但经过简化

© www.soinside.com 2019 - 2024. All rights reserved.