设计社交网络的数据结构

这篇具有很好参考价值的文章主要介绍了设计社交网络的数据结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1: 确定 Use Case 和 约束

Use Cases

  • User 搜索某人然后看到被搜索人的最短路径
  • Service 有高可用

约束和假设

状态假设
  1. Traffic 不是平均分布的
  • 一些被搜索者是更加受欢迎的,某些被搜索者只会被搜索一次
  • 图数据不适用与单个机器
  • 图的分布是轻量级的
  • 一亿个 User
  • 每个 User 平均有 50 个朋友
  • 十亿个搜索每个月

练习使用更传统的系统 - 不要使用 graph-specific solutions, 比如 GraphQL 或者 图数据库 Neo4j

计算使用量
  1. 50 亿 朋友关系
    • 一亿 users * 50 个 friends / user
  2. 每秒 400 个搜索请求

便利转换索引:

  • 每个月250 万秒
  • 1 个请求 / s = 250 万请求 / 月
  • 40 个请求 / s = 1 亿请求 / 月
  • 400 个请求 / s = 10 亿 请求 / 月

2:创建一个 High Level 设计

设计社交网络的数据结构,数据结构,php,开发语言

3: 设计核心组件

Use Case: User 搜索某人,然后得到被搜索人的最短路径

没有上百万 User 和 数十亿 friend 关系的限制,我们可以解决最短路径问题通过使用 BFS 算法

class Graph(Graph):

	def shortest_path(self, source, dest):
		if source is None or dest is None:
			return None
		if source is dest:
			return [source.key]
		prev_node_keys = self._shortest_path(source, dest)
		if prev_node_keys is None:
			return None
		else:
			path_ids = [dest.key]
			prev_node_key = prev_node_keys[dest.key]
			while prev_node_key is not None:
				path_ids.append(prev_node_key)
				prev_node_key = prev_node_keys[prev_node_key]
			return path_ids[::-1]

def _shortest_path(self, source, dest):
	queue = deque()
	queue.append(source)
	prev_node_keys = {source.key: None}
	source.visit_state = State.visited
	while queue:
		node = queue.popleft()
		if node is dest:
			return prev_node_keys
		prev_node = node
		for adj_node in node.adj_nodes.values():
			if adj_node.visit_state == State.unvisted:
				queue.append(adj_node)
				prev_node_keys[adj_node.key] = prev_node.key
				adj_node.visit_state = State.visited
		return Node

我们不能把所有的 User 都放在同一个机器里面,我们需要 分片的 User (通过 Person Server)
而且使用 Lookup Service 去访问他们

  1. Client 发送请求到 Web Server
  2. Web Server 转发请求到 Search API server
  3. Search API server 转发请求到 User Graph Service
  4. User Graph Service 做下面的事情:
    • 使用 Lookup Service 去寻找 Person Server, 当当前 User的info 被存储过后
    • 寻找合适的 Person Server去接收当前 User的 friend_ids 的 list
    • 运行 BFS 搜索(使用当前 User 作为 source, 而且当前 User的 friend_ids 作为 ids)
    • 从给定的 id 获取 adjacent_node
      • User Graph Service 将需要再次和 Lookup Service沟通,去决定哪一个 Person Service 存储 adjecent_node 数据(匹配给定的 id)

Lookup Service 实现:

class LookupService(object):

    def __init__(self):
        self.lookup = self._init_lookup()  # key: person_id, value: person_server

    def _init_lookup(self):
        ...

    def lookup_person_server(self, person_id):
        return self.lookup[person_id]

Person Server 实现:

class PersonServer(object):

    def __init__(self):
        self.people = {}  # key: person_id, value: person

    def add_person(self, person):
        ...

    def people(self, ids):
        results = []
        for id in ids:
            if id in self.people:
                results.append(self.people[id])
        return results

Person 实现:

class Person(object):
	def __init__(self, id, name, friend_ids):
		self.id = id
		self.name = name
		self.friend_ids = friend_ids

User Graph Service 实现:

class UserGraphService(object):

    def __init__(self, lookup_service):
        self.lookup_service = lookup_service

    def person(self, person_id):
        person_server = self.lookup_service.lookup_person_server(person_id)
        return person_server.people([person_id])

    def shortest_path(self, source_key, dest_key):
        if source_key is None or dest_key is None:
            return None
        if source_key is dest_key:
            return [source_key]
        prev_node_keys = self._shortest_path(source_key, dest_key)
        if prev_node_keys is None:
            return None
        else:
            # Iterate through the path_ids backwards, starting at dest_key
            path_ids = [dest_key]
            prev_node_key = prev_node_keys[dest_key]
            while prev_node_key is not None:
                path_ids.append(prev_node_key)
                prev_node_key = prev_node_keys[prev_node_key]
            # Reverse the list since we iterated backwards
            return path_ids[::-1]

    def _shortest_path(self, source_key, dest_key, path):
        # Use the id to get the Person
        source = self.person(source_key)
        # Update our bfs queue
        queue = deque()
        queue.append(source)
        # prev_node_keys keeps track of each hop from
        # the source_key to the dest_key
        prev_node_keys = {source_key: None}
        # We'll use visited_ids to keep track of which nodes we've
        # visited, which can be different from a typical bfs where
        # this can be stored in the node itself
        visited_ids = set()
        visited_ids.add(source.id)
        while queue:
            node = queue.popleft()
            if node.key is dest_key:
                return prev_node_keys
            prev_node = node
            for friend_id in node.friend_ids:
                if friend_id not in visited_ids:
                    friend_node = self.person(friend_id)
                    queue.append(friend_node)
                    prev_node_keys[friend_id] = prev_node.key
                    visited_ids.add(friend_id)
        return None

我们可以使用 public REST API:

$ curl https://social.com/api/v1/friend_search?person_id=1234

Response:

{
    "person_id": "100",
    "name": "foo",
    "link": "https://social.com/foo",
},
{
    "person_id": "53",
    "name": "bar",
    "link": "https://social.com/bar",
},
{
    "person_id": "1234",
    "name": "baz",
    "link": "https://social.com/baz",
}

4: 扩展设计

设计社交网络的数据结构,数据结构,php,开发语言

我们可以有以下优化点:文章来源地址https://www.toymoban.com/news/detail-807523.html

  • 存储完整或部分BFS遍历,以加速后续在内存缓存中的查找
  • 批处理计算然后存储完整或部分BFS遍历,加速在 NoSQL 数据库中的子序列查询
  • 减少机器跳跃通过批量查找朋友在同一个域名下的 Person Server
    • 通过Location分片的 Person Server去进一步的提高,正如朋友普遍都住的比较近
  • 在同一时刻做两个 BFS 搜索,一个从 source开始,另一个从 destination 开始,然后 merge 这量个 path
  • 人们从 BFS 开始搜索大量的 friend. 然后他们是更喜欢去减少 分页的数字(在当前用户和搜索结果)
  • 在询问用户是否要继续搜索之前,根据时间或跳数设置一个限制,因为在某些情况下,搜索可能需要相当长的时间
  • 使用Neo4j等图形数据库或GraphQL等特定于图形的查询语言(如果没有限制阻止使用图形数据库)

到了这里,关于设计社交网络的数据结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构课程设计】关键路径问题

    1 问题描述与功能需求分析 1.1问题描述 1) 任务:设计一个程序求出完成整项工程至少需要多少时间以及整项工程中的关键活动。 2)基本要求: (1)对一个描述工程的 AOE 网,应判断其是否能够顺利进行。 (2)若该工程能顺利进行,输出完成整项工程至少需要多少时间,以及

    2024年02月10日
    浏览(33)
  • 【数据结构与算法】设计循环队列

      🧑‍🎓 个人主页:简 料   🏆 所属专栏:C++   🏆 个人社区:越努力越幸运社区   🏆 简       介: 简料简料,简单有料~在校大学生一枚,专注C/C++/GO的干货分享,立志成为您的好帮手 ~ C/C++学习路线 (点击解锁) ❤️ C语言阶段(已结束) ❤️ 数据结构与算法(ing) ❤

    2024年01月17日
    浏览(33)
  • 数据结构课程设计 ——考试报名系统

    数据结构课程设计 ——考试报名系统 一、项目功能要求 完成对考生信息的建立,查找,插入,修改,删除等功能。其中考生信息包括准考证号,姓名,性别,年龄和报考类别等信息。项目在设计时应首先确定系统的数据结构,定义类的成员变量和成员函数;然后实现各成员

    2024年02月04日
    浏览(36)
  • 数据结构课程设计1: 区块链

    1.任务: [问题描述] 使用链表设计一个保存信息的系统,该系统拥有类似区块链的设计以防止信息被轻易篡改。 该题目使用一个链表。信息保存在链表的每一个节点中,每个节点需要包含该节点的编号、信息和校验码。其中: + 每个节点的编号按照顺序递增,从0开始。 + 节

    2023年04月16日
    浏览(94)
  • 数据结构OJ:设计循环队列

    本题为LeetCode上的经典题目,题目要求我们设计一种循环队列,满足FIFO原则且队尾被连接在队首之后。 题目中介绍循环队列的好处是可以重复利用空间,所以我们很容易想到在初始化时即开辟指定大小的空间,之后便不需要再开辟空间,只需后续销毁即可。 首先我们要选择

    2024年04月17日
    浏览(49)
  • 【数据结构实训】哈希表设计

    [问题描述] 针对某个集体中人名设计一个哈希表,使得平均查找长度不超过2,并完成相应的建表和查表程序。 [基本要求] 假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个,取平均查找长度的上限为2。哈希函数用除留余数法构造,用线性探测再散列法或

    2024年02月11日
    浏览(31)
  • 设计模式⑥ :访问数据结构

    有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写\\\"抄书\\\"系列。本系列大部分内容都是来源于《 图解设计模式》(【日】结城浩 著)。该系列文章可随意转载。 Visitor 模式:访问数据结构并处理数据 在 Visitor 模式中,数据结构

    2024年01月16日
    浏览(36)
  • 数据结构设计--学生信息管理系统

    目录 1.环境 2.知识图 3.程序的功能 4.程序的源代码 vs code 快排+哈希 (1)程序中的数据存储到文件中。 (2) 录入学生成绩,格式如下: (学号(12位) 、姓名、性别、专业、班级、课程成绩(5门课程),总分)其中,总分通过程序计算求得。 (3)输出所有学生成绩。 (a)按某门课程成绩降序

    2024年02月04日
    浏览(34)
  • 数据结构课程设计 仓储管理系统

    【基本功能】 把货品信息表抽象成一个线性表,货品信息(包括ID、货品名、定价、数量等)作为线性表的一个元素,实现:按ID、货品名分别查找某货品信息(包括ID、货品名、定价、数量等);收录货品(如果货品在帐中已有,则只将总库存量增加。否则插入新增信息);

    2024年01月23日
    浏览(43)
  • 数据结构算法设计——哈希表(散列表)

            哈希表 又叫 散列表 ,他们两个是同一个东西,本文全文采用“散列表”的叫法。散列表的本质其实就是一个 数组 ,他的作用就像使用数组时一样,输入下标可以得到对应元素,散列表可以实现 输入一个的时候得到这个的地址信息 。 下面是百科给出

    2024年02月03日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包