9

Python Boto 2.3.0でアトミックカウントカウンターを更新しようとしていますが、操作のドキュメントが見つかりません。

直接のインターフェースがないようですので、layer1インターフェースを使って「生の」アップデートに行こうとしましたが、単純なアップデートでも完了できませんでした。

私は次のバリエーションを試しましたが、すべて運がありませんでした

dynoConn.update_item(INFLUENCER_DATA_TABLE, 
                     {'HashKeyElement': "9f08b4f5-d25a-4950-a948-0381c34aed1c"}, 
                     {'new': {'Value': {'N':"1"}, 'Action': "ADD"}})    

dynoConn.update_item('influencer_data', 
                     {'HashKeyElement': "9f08b4f5-d25a-4950-a948-0381c34aed1c"}, 
                     {'new': {'S' :'hello'}})                                 

dynoConn.update_item("influencer_data", 
                     {"HashKeyElement": "9f08b4f5-d25a-4950-a948-0381c34aed1c"},
                     {"AttributesToPut" : {"new": {"S" :"hello"}}})      

それらはすべて同じエラーを生成します:

  File "/usr/local/lib/python2.6/dist-packages/boto-2.3.0-py2.6.egg/boto/dynamodb/layer1.py", line 164, in _retry_handler
    data)
boto.exception.DynamoDBResponseError: DynamoDBResponseError: 400 Bad Request
{u'Message': u'Expected null', u'__type': u'com.amazon.coral.service#SerializationException'}

ここでAPIドキュメントも調べましたが、かなり質素でした。

私は多くの検索と操作を行いました。残っているのは、PHP APIを使用してコードを調べ、JSON本体を「フォーマット」する場所を見つけることだけですが、それは少し面倒です。その痛みから私を救ってください!

4

5 に答える 5

12

すみません、あなたが探していたものを誤解しました。対処する必要のある小さなバグがありますが、layer2を介してこれを達成できます。次に、いくつかのLayer2コードを示します。

>>> import boto
>>> c = boto.connect_dynamodb()
>>> t = c.get_table('counter')
>>> item = t.get_item('counter')
>>> item
{u'id': 'counter', u'n': 1}
>>> item.add_attribute('n', 20)
>>> item.save()
{u'ConsumedCapacityUnits': 1.0}
>>> item  # Here's the bug, local Item is not updated
{u'id': 'counter', u'n': 1}
>>> item = t.get_item('counter')  # Refetch item just to verify change occurred
>>> item
{u'id': 'counter', u'n': 21}

これにより、次のデバッグ出力に示すように、Layer1コードで実行しているのと同じ有線要求が発生します。

2012-04-27 04:17:59,170 foo [DEBUG]:StringToSign:
POST
/

host:dynamodb.us-east-1.amazonaws.com
x-amz-date:Fri, 27 Apr 2012 11:17:59 GMT
x-amz-security-    token:<removed> ==
x-amz-target:DynamoDB_20111205.UpdateItem

{"AttributeUpdates": {"n": {"Action": "ADD", "Value": {"N": "20"}}}, "TableName": "counter", "Key": {"HashKeyElement": {"S": "counter"}}}

最初のGetItem呼び出しを避けたい場合は、代わりにこれを行うことができます。

>>> import boto
>>> c = boto.connect_dynamodb()
>>> t = c.get_table('counter')
>>> item = t.new_item('counter')
>>> item.add_attribute('n', 20)
>>> item.save()
{u'ConsumedCapacityUnits': 1.0}

アイテムがすでに存在する場合は更新し、まだ存在しない場合は作成します。

于 2012-04-27T11:25:41.983 に答える
5

答えを探している人のために、私はそれを見つけました。最初の重要な注意、私は現在何が起こっているのかわかりませんが、レイヤー1インスタンスを取得するには、次のことをしなければなりませんでした:

import boto
AWS_ACCESS_KEY=XXXXX
AWS_SECRET_KEY=YYYYY
dynoConn = boto.connect_dynamodb(AWS_ACCESS_KEY, AWS_SECRET_KEY)
dynoConnLayer1 = boto.dynamodb.layer1.Layer1(AWS_ACCESS_KEY, AWS_SECRET_KEY) 

基本的に、最初にレイヤー2をインスタンス化し、次にレイヤー1をインスタンス化します。おそらく私は何か愚かなことをしていますが、この時点では、それが機能することを嬉しく思います....詳細は後でソートします。THEN ...実際にアトミック更新呼び出しを実行するには:

dynoConnLayer1.update_item("influencer_data", 
                    {"HashKeyElement":{"S":"9f08b4f5-d25a-4950-a948-0381c34aed1c"}},
                    {"direct_influence":
                        {"Action":"ADD","Value":{"N":"20"}}
                    }
                );

上記の例では、Dynamo は現在の値に 20 を加算します。この操作はアトミックです。つまり、「同時に」発生する他の操作は、新しい値が +20 として確立された後に発生するように正しく「スケジュール」されます。または、この操作が実行される前。どちらの方法でも、目的の効果が達成されます。

異なるパラメータ タイプのセットを想定している場合、layer2 はエラーをスローするため、layer1 接続のインスタンスでこれを行うようにしてください。

それだけです!皆さんが知っているように、私は PHP SDK を使用してこれを理解しました。インストールと設定に非常に短い時間がかかり、呼び出しを行うと、デバッグ データが実際に HTTP 要求本文の形式を表示するため、例の後にレイヤー 1 パラメーターをコピー/モデル化できます。PHP でアトミックな更新を行うために使用したコードは次のとおりです。

<?php 
    // Instantiate the class
    $dynamodb = new AmazonDynamoDB();

    $update_response = $dynamodb->update_item(array(
        'TableName' => 'influencer_data',
            'Key' => array(
                'HashKeyElement' => array(
                    AmazonDynamoDB::TYPE_STRING=> '9f08b4f5-d25a-4950-a948-0381c34aed1c'
                )
            ),
            'AttributeUpdates' => array(
                'direct_influence' => array(
                    'Action' => AmazonDynamoDB::ACTION_ADD,
                    'Value' => array(
                        AmazonDynamoDB::TYPE_NUMBER => '20'
                    )
                )
            )
    ));

    // status code 200 indicates success
    print_r($update_response);

?>

うまくいけば、これは Boto レイヤー 2 インターフェイスが追いつくまで他の人を助けるでしょう... または誰かがレベル 2 でそれを行う方法を単純に理解する :-)

于 2012-04-27T05:06:33.697 に答える
0

DynamoDBには、アトミックカウンター用の高レベルの関数はありません。ただし、条件付き書き込み機能を使用してアトミックカウンターを実装できます。たとえば、このように呼び出された文字列ハッシュキーを持つテーブルがあるとします。

>>> import boto
>>> c = boto.connect_dynamodb()
>>> schema = s.create_schema('id', 's')
>>> counter_table = c.create_table('counter', schema, 5, 5)

ここで、値がゼロの「n」という属性を含むアイテムをそのテーブルに書き込みます。

>>> n = 0
>>> item = counter_table.new_item('counter', {'n': n})
>>> item.put()

ここで、カウンターの値を更新する場合は、現在の値が現在の値の考え方と一致する場合に、「n」の値を1に上げる条件付き書き込み操作を実行します。

>>> n += 1
>>> item['n'] = n
>>> item.put(expected_value={'n': n-1})

これにより、アイテムの「n」の値が1に設定されますが、DynamoDBの現在の値がゼロの場合に限ります。値がすでに他の誰かによってインクリメントされている場合、書き込みは失敗し、ローカルカウンターでインクリメントして再試行する必要があります。

これはちょっと複雑ですが、これらすべてをいくつかのコードにまとめて、はるかに簡単に使用できるようにすることができます。SimpleDBについても、ここで見つけることができる同様のことを行いました。

http://www.elastician.com/2010/02/stupid-boto-tricks-2-reliable-counters.html

DynamoDBを使用するようにその例を更新してみるべきでしょう

于 2012-04-26T17:13:27.650 に答える
0

dynamodb の値を増やしたい場合は、次を使用してこれを実現できます。

import boto3
import json
import decimal

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)

ddb = boto3.resource('dynamodb') 
def get_counter():
    table = ddb.Table(TableName)
    try:
            response = table.update_item(                                                             
            Key={
                'haskey' : 'counterName'
            },
            UpdateExpression="set currentValue = currentValue +  :val",
            ExpressionAttributeValues={
                ':val': decimal.Decimal(1)
            }, 
            ReturnValues="UPDATED_NEW"
        )
        print("UpdateItem succeeded:")
    except Exception as e:
        raise e
    print(response["Attributes"]["currentValue" ])

この実装には、最後に使用された値を保持する追加のカウンター テーブルが必要です。

于 2019-12-04T10:30:47.507 に答える