1

我正在尝试使用 DynamoDB 表来存储这些数据:

DartsPlayerInsultTable

CustomerId   String

PlayerId     String

PlayerInsult String

使用此处描述的方法(概念,而不是代码):

https://java.awsblog.com/post/Tx3GYZEVGO924K4/The-DynamoDBMapper-Local-Secondary-Indexes-and-You

这里:

http://mobile.awsblog.com/post/TxTCW7KW8BGZAF/Amazon-DynamoDB-on-Mobile-Part-4-Local-Secondary-Indexes

和这里:

http://labs.journwe.com/2013/12/15/dynamodb-secondary-indexes/comment-page-1/#comment-116

我希望每个客户玩家有多个侮辱记录。CustomerId 是我的哈希键 PlayerId 是我的范围键,我试图在键中使用 PlayerInsult,以便第二个 PlayerInsult 值插入第二条记录,而不是替换现有的记录。

为此尝试了全局索引和二级索引,但如果我尝试添加新的侮辱行,它仍然会用相同的客户-玩家密钥替换侮辱,而不是添加新的。

DynanoDB 对此的最佳使用方法有什么建议吗?我是否需要为范围键创建混合列?试图保持这个简单...

class func createDartsPlayerInsultTable() -> BFTask {
    let dynamoDB = AWSDynamoDB.defaultDynamoDB()

    let hashKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
    hashKeyAttributeDefinition.attributeName = "CustomerId"
    hashKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S

    let hashKeySchemaElement = AWSDynamoDBKeySchemaElement()
    hashKeySchemaElement.attributeName = "CustomerId"
    hashKeySchemaElement.keyType = AWSDynamoDBKeyType.Hash

    let rangeKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
    rangeKeyAttributeDefinition.attributeName = "PlayerId"
    rangeKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S

    let rangeKeySchemaElement = AWSDynamoDBKeySchemaElement()
    rangeKeySchemaElement.attributeName = "PlayerId"
    rangeKeySchemaElement.keyType = AWSDynamoDBKeyType.Range

    /*
    let indexRangeKeyAttributeDefinition = AWSDynamoDBAttributeDefinition()
    indexRangeKeyAttributeDefinition.attributeName = "PlayerInsult"
    indexRangeKeyAttributeDefinition.attributeType = AWSDynamoDBScalarAttributeType.S

    let rangeKeySchemaElement = AWSDynamoDBKeySchemaElement()
    rangeKeySchemaElement.attributeName = "PlayerId"
    rangeKeySchemaElement.keyType = AWSDynamoDBKeyType.Range

    let indexRangeKeyElement =  AWSDynamoDBKeySchemaElement()
    indexRangeKeyElement.attributeName = "PlayerInsult"
    indexRangeKeyElement.keyType = AWSDynamoDBIndexRangeKeyType.
    */

    //Add non-key attributes
    let playerInsultAttrDef = AWSDynamoDBAttributeDefinition()
    playerInsultAttrDef.attributeName = "PlayerInsult"
    playerInsultAttrDef.attributeType = AWSDynamoDBScalarAttributeType.S

    let provisionedThroughput = AWSDynamoDBProvisionedThroughput()
    provisionedThroughput.readCapacityUnits = 5
    provisionedThroughput.writeCapacityUnits = 5

    // CREATE GLOBAL SECONDARY INDEX
    /*
    let gsi = AWSDynamoDBGlobalSecondaryIndex()
    let gsiArray = NSMutableArray()

    let gsiHashKeySchema = AWSDynamoDBKeySchemaElement()
    gsiHashKeySchema.attributeName = "PlayerId"
    gsiHashKeySchema.keyType = AWSDynamoDBKeyType.Hash

    let gsiRangeKeySchema = AWSDynamoDBKeySchemaElement()
    gsiRangeKeySchema.attributeName = "PlayerInsult"
    gsiRangeKeySchema.keyType = AWSDynamoDBKeyType.Range

    let gsiProjection = AWSDynamoDBProjection()
    gsiProjection.projectionType = AWSDynamoDBProjectionType.All;

    gsi.keySchema = [gsiHashKeySchema,gsiRangeKeySchema];
    gsi.indexName = "PlayerInsult";
    gsi.projection = gsiProjection;
    gsi.provisionedThroughput = provisionedThroughput;

    gsiArray .addObject(gsi)
    */

    // CREATE LOCAL SECONDARY INDEX

    let lsi = AWSDynamoDBLocalSecondaryIndex()
    let lsiArray = NSMutableArray()

    let lsiHashKeySchema = AWSDynamoDBKeySchemaElement()
    lsiHashKeySchema.attributeName = "CustomerId"
    lsiHashKeySchema.keyType = AWSDynamoDBKeyType.Hash

    let lsiRangeKeySchema = AWSDynamoDBKeySchemaElement()
    lsiRangeKeySchema.attributeName = "PlayerInsult"
    lsiRangeKeySchema.keyType = AWSDynamoDBKeyType.Range

    let lsiProjection = AWSDynamoDBProjection()
    lsiProjection.projectionType = AWSDynamoDBProjectionType.All;

    lsi.keySchema = [lsiHashKeySchema,lsiRangeKeySchema];
    lsi.indexName = "PlayerInsult";
    lsi.projection = lsiProjection;
    //lsi.provisionedThroughput = provisionedThroughput;

    lsiArray .addObject(lsi)


    //Create TableInput
    let createTableInput = AWSDynamoDBCreateTableInput()
    createTableInput.tableName = DartsPlayerInsultTableName;
    createTableInput.attributeDefinitions = [hashKeyAttributeDefinition, rangeKeyAttributeDefinition, playerInsultAttrDef]
    //createTableInput.attributeDefinitions = [hashKeyAttributeDefinition, rangeKeyAttributeDefinition]
    createTableInput.keySchema = [hashKeySchemaElement, rangeKeySchemaElement]
    createTableInput.provisionedThroughput = provisionedThroughput
    //createTableInput.globalSecondaryIndexes = gsiArray as [AnyObject]
    createTableInput.localSecondaryIndexes = lsiArray as [AnyObject]

    return dynamoDB.createTable(createTableInput).continueWithSuccessBlock({ (var task:BFTask!) -> AnyObject! in
        if ((task.result) != nil) {
            // Wait for up to 4 minutes until the table becomes ACTIVE.

            let describeTableInput = AWSDynamoDBDescribeTableInput()
            describeTableInput.tableName = DartsPlayerInsultTableName;
            task = dynamoDB.describeTable(describeTableInput)

            for var i = 0; i < 16; i++ {
                task = task.continueWithSuccessBlock({ (task:BFTask!) -> AnyObject! in
                    let describeTableOutput:AWSDynamoDBDescribeTableOutput = task.result as! AWSDynamoDBDescribeTableOutput
                    let tableStatus = describeTableOutput.table.tableStatus
                    if tableStatus == AWSDynamoDBTableStatus.Active {
                        return task
                    }

                    sleep(15)
                    return dynamoDB .describeTable(describeTableInput)
                })
            }
        }

        return task
    })

}
4

2 回答 2

0

我决定做的是只用一个哈希键制作一个传统的 dynamodb 表,但新的哈希键是一个组合字符串:

客户 ID +“|” + 玩家编号

保持玩家和侮辱表之间的同步并不难,因为一旦将玩家插入到玩家表中,修改玩家名称会导致插入新行。因此,如果玩家名称更改,则无需修改侮辱。如果玩家被删除,您只需要清理侮辱。

如果您将 Player 名称设置为哈希键,则此更新行为就是 dynamodb 的工作方式,我这样做是为了确保它们是唯一的。

于 2015-09-22T19:17:43.550 回答
0

把它作为一个答案,而不是另一个评论,以防它变得很长......

听起来普通用户的侮辱可能适合单个记录。由于我对 swift 一无所知的免责声明,这可能至少是相对简单的事情。保留您的客户和玩家密钥。在你坚持侮辱之前,使用任何版本的 join("|") swift 将整个列表变成一个大字符串。当您获取记录时,请执行 split("|") 以获取您的列表。(请谨慎选择分隔符,我仅使用“|”作为示例,您不想选择可能出现在侮辱中的内容...)

会有一个用户有足够的侮辱让你超过 400kb 的对象限制。在您的代码中设置一个最大列表大小常量——当您将列表转换为字符串以将它们保存到发电机时,请根据该限制检查播放器的列表长度。如果超过它,请将列表分成该大小的块并使用哈希和范围键,例如 ("foo", "bar"), ("foo", "bar1"), ("foo", "bar2"),等等。是的,第一个最后没有号......

当您查询数据时,只需先进行直接查询并假设您的情况很好(只有“foo”和“bar”,没有其他存储桶)。当你打开第一个列表时,检查它的长度。如果它等于您的最大列表大小常量,则您知道您有一个“坏”用户并且需要进行范围查询。第二个可以使用哈希键“foo”和范围“bar”到“bar9999”。您将使用该范围查询取回所有这些存储桶。解包并连接所有列表。

这有点血腥,但最终也应该直接编写代码。希望它仍然足够简单,可以融入您提到的模式。

于 2015-09-21T23:51:37.807 回答