java 社交网站、博客等用户头像是怎么存储的?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 社交网站、博客等用户头像是怎么存储的?相关的知识,希望对你有一定的参考价值。
是把图片存本地,数据库存url 呢?还是把图片弄成数据流直接存到数据库表里?
参考技术A 图片存在专门的资源服务器上,数据库存url,带域名的完整url本回答被提问者和网友采纳 参考技术B 都可以啊,看你具体的情况了!如果两种情况对你都没影响自然是怎么简单怎么处理了!追问哪种方式简单些?
您将如何为 Twitter 等社交网站设计 AppEngine 数据存储?
【中文标题】您将如何为 Twitter 等社交网站设计 AppEngine 数据存储?【英文标题】:How would you design an AppEngine datastore for a social site like Twitter? 【发布时间】:2010-12-10 10:44:12 【问题描述】:我想知道设计一个社交应用程序的最佳方式是什么,让成员可以使用 Google AppEngine 进行活动并关注其他成员的活动。
更具体地说,假设我们有这些实体:
有朋友的用户 Activity 代表用户所做的操作(假设每个都有一个字符串消息和一个对其所有者用户的 ReferenceProperty,或者它可以通过 appengine 的密钥使用父关联)最困难的部分是关注您朋友的活动,这意味着汇总您所有朋友的最新活动。 通常,这将是活动表和您的朋友列表之间的连接,但这在 appengine 上不是一个可行的设计,因为没有连接模拟它需要启动 N 个查询(其中 N 是朋友的数量),然后在内存中合并 -非常昂贵,可能会超过请求期限...)
我目前正在考虑使用收件箱队列来实现这一点,其中创建新 Activity 将触发一个后台进程,该进程会将新 Activity 的密钥放入每个以下用户的“收件箱”中:
获取“所有关注 X 的用户”是一个可能的 appengine 查询 对于基本上存储(用户、活动键)元组的新“收件箱”实体的批量输入并不是非常昂贵。我很高兴听到对此设计的想法或替代建议等。
【问题讨论】:
我正在研究同样的问题,并从 AppEngine 中发现了这个出色的(!)演示文稿,他们在 Google I/O 上提供了该演示文稿:scribd.com/doc/16952419/… 我希望你也会发现它也很有用。 【参考方案1】:看看Building Scalable, Complex Apps on App Engine (pdf),这是 Brett Slatkin 在 Google I/O 上发表的精彩演讲。他解决了构建像 Twitter 这样的可扩展消息服务的问题。
这是他使用列表属性的解决方案:
class Message(db.Model):
sender = db.StringProperty()
body = db.TextProperty()
class MessageIndex(db.Model):
#parent = a message
receivers = db.StringListProperty()
indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)
此键仅查询查找接收方等于您指定的接收方的消息索引,而无需反序列化和序列化接收方列表。然后,您使用这些索引仅获取您想要的消息。
这是错误的方法:
class Message(db.Model):
sender = db.StringProperty()
receivers = db.StringListProperty()
body = db.TextProperty()
messages = Message.all().filter('receivers =', user_id)
这是低效的,因为查询必须解包查询返回的所有结果。因此,如果您返回 100 条消息,每个接收者列表中有 1,000 个用户,则您必须反序列化 100,000 (100 x 1000) 个列表属性值。数据存储延迟和 CPU 成本太高了。
一开始我对这一切感到很困惑,所以我写了一个short tutorial about using the list property。享受:)
【讨论】:
正是我最初的设计。但我从那次谈话和 AppEngine 文档中了解到,在 IN 查询中,列表是毫无用处的。您提到的查询将在 google 系统中触发多个查询,每个查询都通过列表属性中的一个值进行过滤,然后合并结果。 Google 将此类查询限制为 30 个同时查询,这意味着它只能用于包含相对较少数量的键 ( 顺便说一句,我问过你关于你发布的另一个 *** 问题中的列表的相同问题 :) 我认为这不对。 Brett 说,当他谈到列表属性性能时,每个实体的索引属性限制为 5000 个(参见视频中的 14:15)。我认为您应该能够在接收器 StringListProperty 中拥有数千个用户,同时仍然能够执行有效的查询。我不确定“包含 != 或 IN 运算符的单个查询限制为 30 个子查询”这一行是什么意思,但我肯定它不会影响您在此处执行的操作。 GQL IN 运算符(根据文档限制为 30 个项目)和此处使用的过滤器(根据演示文稿将适用于大型列表)有什么区别? 'IN' 是“查找包含这些值之一的任何实体”,它被拆分为 n 个“查找包含此确切值的任何实体”查询。然而,列表上的相等过滤器是后者 - “查找具有此精确值的任何实体(可能在列表中)”,因此不会像 IN 查询那样低效。【参考方案2】:我不知道它是否是社交应用程序的最佳设计,但jaiku 在公司被谷歌收购时由它的原始创建者ported to App Engine,所以它应该是合理。
请参阅design_funument.txt 中的演员、老虎和熊,哦,我的!部分。实体在common/models.py 中定义,查询在common/api.py 中。
【讨论】:
【参考方案3】:我认为现在可以通过 NDB 中的新投影查询来解决这个问题。
class Message(ndb.Model):
sender = ndb.StringProperty()
receivers = ndb.StringProperty(repeated=True)
body = ndb.TextProperty()
messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])
现在您不必处理反序列化列表属性的昂贵成本。
【讨论】:
【参考方案4】:罗伯特,关于您提出的解决方案:
messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])
我认为 ndb.TextProperty “body”不能与投影一起使用,因为它没有被索引。投影仅支持索引属性。 有效的解决方案是维护 2 个表:Message 和 MessageIndex。
【讨论】:
以上是关于java 社交网站、博客等用户头像是怎么存储的?的主要内容,如果未能解决你的问题,请参考以下文章