【问题标题】:DynamoDB table design for social network社交网络的 DynamoDB 表设计
【发布时间】:2019-06-12 20:52:01
【问题描述】:

我在 DynamoDB 中遇到了一个思考问题。 我的结构如下所示:

  • 主键 = "id"

  • 排序键 = “排序” 我有帖子、用户和“用户 A 关注用户 B”的关系。

用户:

  • id=1234
  • sort="USER_USER_1234"
  • name="max"(例如)

-

  • id=3245
  • sort="USER_USER_3245"
  • name="tom"

发帖:

  • id=9874

  • sort="POST_POST_1234(因为它是由用户 id 1234 创建的)

  • createdAt=1560371687

以下:

  • id=1234

  • sort="USER_FOLLOW_3245"

--> tom 跟随 max(但 max 不是 tom)

我如何设计一个查询来获取 tom(id=3245) 关注的人的所有帖子?那么在我的情况下,帖子 ID 为 9874? 我的方法是放置一个 GSI,其中 sort 是主键,id 是排序键(我可以查询所有用户 A 关注的人),而不是从用户那里获取所有帖子(在同一个 GSI 的帮助下)和在第二个索引之后对结果进行排序,其中 createdAt 是排序键。问题是这需要很多查询(假设用户 A 会关注 10000 人并且他们都发帖)。对于这种情况,您是否可以推荐一种技术或设计思维方法?我的第二种方法是将整个应用程序表索引到弹性搜索并进行嵌套查询。这会更有意义吗?或者您会推荐使用其他类型的数据库,例如 AWS neptune?

【问题讨论】:

    标签: amazon-web-services amazon-dynamodb dynamodb-queries amazon-neptune


    【解决方案1】:

    在 Amazon Neptune 中,这很简单:

    g.V(3245).E('post')
    

    上述查询将返回一个迭代器,从 ID 为“3245”的顶点开始,到由边缘标签“post”连接的所有顶点。您可以通过从这些顶点投影特定属性 (.property('name')) 或具体化整个顶点 (.valueMap()) 来进一步收紧它。这只是 Gremlin 语法,您也可以使用 SPARQL 轻松完成相同的操作,并且 Amazon Neptune 支持这两种语法。

    对您来说更大的问题是评估您希望对数据执行的所有类型的查询,并查看在图形数据库中对其进行建模是否有意义。如果是这样,那么您最好使用 Neptune,而不是使用混合其他产品的定制产品。查询/遍历高度连接的数据、浏览关系等是使用图数据模型的一些经典用例。

    【讨论】:

    • 谢谢伙计!以下关系是唯一有意义的关系。其余的只是 dynamodb 中的一张表,我设计了不需要任何扫描或其他昂贵操作的模式。您认为上述关系可能与弹性有关吗?这在 dynamodb 上运行得非常好,非常适合地理查询,就像我在我的应用程序中得到的一样。
    • 这可能是可能的,但您不是根据帖子的内容查询或搜索,对吧?如果文本搜索是一个重要的用例,那么弹性确实有意义。如果它只是遍历连接,并且如果您最终有可能遍历大图、多跳查询等,那么我会推荐 graph.另外,DDB 如何帮助地理空间查询?
    • 我仅将 Elastic 用于地理查询,如果这是一个误解,请见谅。而且我不是在寻找帖子的内容。
    • 好的,所以您将 Elastic 用于 GeoSpatial - 这是有道理的。地理空间查询也是图形的一个主要用例(例如,已经有 SPARQL 词汇表来模拟纬度和经度),但我认为 Neptune 没有任何开箱即用的东西可以让您立即受益于地理查询。很好奇 - 对于数据模型,DDB 为您提供了哪些图形数据库所没有的优势?
    • 如果你想完全实现你的行,那么是的,DDB 是一个不错的选择。如果您只想投影一些字段并以此为基础进行过滤/遍历,您会在 Neptune 中看到提升。祝您实验顺利,并分享结果。
    【解决方案2】:

    AWS 上有一个关于类似问题的动手实验室 - “包含社交网络的移动应用程序”:https://aws.amazon.com/getting-started/hands-on/design-a-database-for-a-mobile-app-with-dynamodb/4/

    简要说明:

    1. 用户将通过您的应用上传照片
    2. 用户希望找到并关注朋友
    3. 关注好友后,用户将收到好友新照片的通知
    4. 用户将能够向他们的朋友发送消息
    5. 朋友可以查看他们的照片
    6. 用户可以使用四种表情符号之一对照片做出反应——心形、笑脸、竖起大拇指或一副太阳镜。
    7. 查看照片时,用户应该能够看到照片收到的每种类型反应的数量

    该模型具有以下实体:UserPhotoReactionFriendship

    一个User 可以有多个Photos,一个Photo 可以有多个Reactions。最后,Friendship 实体代表了用户之间的多对多关系,因为一个用户可以关注多个用户,也可以被多个其他用户关注。

    访问模式

    根据业务需求,这些是确定的访问模式:

    用户

    1. 创建用户配置文件(写入)
    2. 更新用户资料(写入)
    3. 获取用户配置文件(读取)

    照片

    1. 为用户上传照片(写)
    2. 查看用户最近的照片(阅读)
    3. 对照片做出反应(写)
    4. 查看照片和反应(阅读)

    友谊

    用户可以关注朋友,查看他们朋友的活动更新,并接收他们可能想要关注的其他朋友的推荐。

    友谊是一种单向的关系,就像 Twitter。一个用户可以选择关注另一个用户,并且该用户可以选择关注该用户。对于我们的应用程序,我们将关注用户的用户称为“关注者”,将用户关注的用户称为“关注者”。

    根据这些信息,我们有以下访问模式:

    1. 关注用户(写)
    2. 查看用户的关注者(阅读)
    3. 用户关注的视图(读取)

    在 Friendship 实体上,我们有一个访问模式需要查找关注特定用户的所有用户,以及一个访问模式来查找给定用户关注的所有用户。

    餐桌设计

    因此,我们将使用具有 PK 和 SK 值的复合主键。复合主键将为我们提供 PK 上的查询能力,以满足我们需要的查询模式之一:

    Entity               PK                  SK
    
    User          USER#<USERNAME>          #METADATA#<USERNAME>
    
    Photo         USER#<USERNAME>.         PHOTO#<USERNAME>#<TIMESTAMP>
    
    Reaction  REACTION#<USERNAME>#<TYPE>   PHOTO#<USERNAME>#<TIMESTAMP>
    
    Friendship    USER#<USERNAME>          #FRIEND#<FRIEND_USERNAME>
    

    Friendship 实体使用与 User 实体相同的 PK。这将允许您在单个查询中获取用户的元数据以及用户的所有关注者:

        KeyConditionExpression="PK = :pk AND SK BETWEEN :metadata AND :photos",
        ExpressionAttributeValues={
            ":pk": { "S": "USER#{}".format(username) },
            ":metadata": { "S": "#METADATA#{}".format(username) },
            ":photos": { "S": "PHOTO$" },
        },
    

    二级(反向)索引对于查询多对多关系的“另一端”很有用。您的友谊实体就是这种情况。使用您的主键结构,您可以通过查询表的主键来查询特定用户的所有关注者。添加倒排索引后,您将能够通过查询倒排索引找到用户正在关注的用户(“已关注”):

        KeyConditionExpression="SK = :sk",
        ExpressionAttributeValues={
            ":sk": { "S": "#FRIEND#{}".format(username) }
        },
    

    扩展

    有趣的是调整设计以支持超受欢迎的用户(拥有数百万追随者)。

    这里没有提到的另一个有趣的访问模式用户提要 - 查看他们的朋友最近发布的所有照片。这可以通过另一个表来完成,以包含此数据流,每当朋友发布某些内容时(查找他的关注者,更新他们的提要...),该数据流就会更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 2016-05-11
      • 2021-04-22
      • 2013-12-18
      • 1970-01-01
      相关资源
      最近更新 更多