DynamoDB:构建和查询带时间戳的日志排序列表的最佳方式是什么?



为了更好地理解亚马逊的DynamoDB、Lambda函数和IAM角色(在这个问题中,我将坚持使用DynamoDB),我正在设置一个Linux设备来监听新的DynamoDB项目,并定期以声音读取其他函数添加的更新。我的目标是查询或扫描项目,从特定的时间戳(设备上次检查的时间)开始按升序返回这些项目。

以下是我目前使用的项目结构:

{
  "id": {
    "S": "1eb4520d44715b6daa5f9d907fe43aab" //md5sum of "time"
  },
  "message": {
    "S": "I'm creating the audible reporting log now."
  },
  "status": {
    "S": "working"
  },
  "time": {
    "S": "1452297505" //timestamp: should probably add milliseconds for sake of unique "id"
  }
}

"id"是分区键。"时间"是排序键。现在来看这个,我想我可能应该把"时间"设为一个数字,而不是字符串。。。

查询还是扫描?查询似乎是正确的排序选项,但它需要在查询中有一个特定的分区ID(至少在AWS网站查询工具中是这样),所以我可能添加错误了。扫描加载所有项目,我猜排序不是自动的,也不是一个选项(至少在AWS网站查询工具中没有)。我真的只想加载大于时间戳值的项目,排序。

我在想什么?我感谢事先的帮助。

更新

在对AWS-CLI和DynamoDB进行进一步的实验后,我最终使用了一个略有不同的解决方案。由于这是一个小规模的"helloworld"类型的项目,因此目前所有更新项都使用一个分区键"SFReporter"添加到同一个表中。如果我决定开始使用单独的查询和/或设备监控额外的"报告器"/服务更新,这可能会扩大。

{
  "datetime": { //sort key
    "S": "2016-01-11T05:15:02"
  },
  "message": {
    "S": "It is all good."
  },
  "reporter": { //primary partition key
    "S": "SF Reporter"
  },
  "status": {
    "S": "ok"
  }
}

JSON查询本身看起来像这样(缩写为node.js示例):

var AWS = require("aws-sdk");
AWS.config.credentials = new AWS.SharedIniFileCredentials({ profile: 'default' });
AWS.config.update({"region": "us-west-2"});
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
    TableName: "spoken_reports",
    KeyConditionExpression: "#reporter = :reporter and #datetime >= :datetime",
    ExpressionAttributeNames:{
        "#reporter": "reporter",
        "#datetime": "datetime"
    },
    ExpressionAttributeValues: {
        ":reporter":"SF Reporter",
        ":datetime":"2016-01-11T05:15:02"
    }
};
docClient.query(params, onUpdatesReceived);
var onUpdatesReceived = function(err, data) { 
    if (err) {
        console.log(err, err.stack);
    } else {
        console.log(data);
    }
}

查询获取按字符串时间戳排序的最新更新(在本例中默认为升序)。这允许进行一些扩展,因为我可以让多个设备检查同一个表中的最新更新。我会创建一个定时查询/函数来偶尔清除旧的更新,以保持轻松。

非常简单的方法:

您应该设置一个全局辅助索引,并将"isNew"作为其主/哈希键,将时间戳作为范围键。

创建条目时,将isNew标记为UUID或其他什么。这将使表项项目进入索引。

当您需要检查数据时,scan是辅助索引-该索引将只具有新的结果。然后,updateItem在表本身中读取的项,以删除该项上的isNew键。该项将从辅助索引中删除,因此不会再次读取。

如果你坚持这种表设计,扫描整个表是你唯一的选择,原因你已经提到:为了查询,你需要一个分区键,这是你的设备事先无法知道的。

我想到了另一个解决方案:

  • 假设您当前的表名为T1。创建另一个表T2,它将deviceID作为分区键,timestamp作为排序键
  • 您在T1的流上定义了一个AWS Lambda函数,该函数在任何更新时都会在T2中推送该行,每个设备一个
  • 现在,每当你的任何设备醒来时,它都会用自己的设备id查询(而不是扫描)T2。处理所有行并删除它们

换句话说,T2将始终具有给定设备尚未处理的所有行。

最新更新