Java 克服google数据存储的30个子查询限制
谷歌数据存储一开始看起来很好,现在变得很令人沮丧,但也许这只是因为我习惯了关系数据库。一般来说,我对数据存储和nosql非常陌生,做了大量的研究,但似乎找不到解决这个问题的方法 假设我有一个如下所示的用户类Java 克服google数据存储的30个子查询限制,java,google-app-engine,google-cloud-datastore,objectify,nosql,Java,Google App Engine,Google Cloud Datastore,Objectify,Nosql,谷歌数据存储一开始看起来很好,现在变得很令人沮丧,但也许这只是因为我习惯了关系数据库。一般来说,我对数据存储和nosql非常陌生,做了大量的研究,但似乎找不到解决这个问题的方法 假设我有一个如下所示的用户类 class User{ @Id Long id; String firstName, lastName; List<Key<User>> friends; } 以此为出发点,我试着去做 // Key<User> userKey = ..
class User{
@Id
Long id;
String firstName, lastName;
List<Key<User>> friends;
}
以此为出发点,我试着去做
// Key<User> userKey = ...
User user = ofy.load.type(User.class).key(userKey).first.now;
List<Key<User>> friends = user.getFriends();
ofy.load.type(Event.class).filter("user in", friends).order("-eventTime")list();
//Key userKey=。。。
User User=ofy.load.type(User.class).key(userKey).first.now;
List friends=user.getFriends();
ofy.load.type(Event.class).filter(“用户在”,朋友们).order(“-eventTime”)list();
但我听说这个30个子查询限制使得这个不可持续,因为我假设最终某人将有30多个朋友,更不用说使用“in”子句将保证您无法获得游标来继续加载事件。我做了很多研究,尝试了很多选择,但除了说“为什么谷歌,为什么”之外,还没有找到解决这个问题的好方法
我考虑过的事情:
- 在事件中添加一个额外的字段,该字段是用户好友列表的副本,并在MVP上使用一个equals来查找事件(因为可能有很多事件,这是非常浪费的)
- 将事件查询一次分成30个好友的批次,以某种方式确定一种方法,以确保根据时间从合成光标中继续检索,并将它们合并(问题是边缘案例太多,使得读取事件非常困难。)
TL;DR~GAE对in子句可以处理多少项和fml有限制。您来自关系数据库背景,因此非规范化的概念可能有点痛苦-我知道这对我来说是很痛苦的 现在,您有一个包含来自所有用户的所有事件的表。这种方法在关系数据库中运行良好,但由于您命名的原因,在数据存储中是一场噩梦 因此,要解决这个具体问题,您可以按如下方式重新构造数据:
- 所有用户都有两条时间线。一条用于他们自己的帖子,另一条来自朋友的帖子。(可能还有第三条用于公共内容的时间线。)
- 发布新事件时,它会写入创建它的用户的时间线,以及接收用户的所有时间线。(您可能希望在用户的时间线中添加第三方时间线的引用,以便在用户决定删除事件时知道要删除什么)
通过这种非规范化,你得到的回报是闪电般的响应和简单的查询。剩下的就是在UI中合并来自不同时间线的响应(你可以在服务器端这样做,但我会在UI中这样做)潜在的兴趣:我也看到了这个,但与我的情况无关,因为他/她将所有新闻故事加载到memcache中,因为新闻对所有登录的用户都是全局的。在我的情况下,事件是由用户创建的,但不是所有用户都看到相同的事件,只有他们自己朋友列表中的人的事件。感谢您的后续关注说到这里,我想用光标标出结果,因为可能会有很多事件,将所有事件加载到memcache中似乎是浪费,因为memcache可能会随时消失。我提到这一点主要是为了回答中的建议。是的,我也在查看这一点,我在问题中提到了我是如何考虑将查询拆分为ba的链接中提到的30个tches。这对新闻来源来说可能很好,但问题是边缘案例太多,无法让它可靠地为我工作。如果前90个朋友几年没有活动会怎么样?他们最近的活动通常不是最近的事件。我想展示最近的30个,但最后的结果是你p关于很久以前的事件。要正确处理这些事件是非常困难的,而且加载很多我不想要的事件也是非常浪费的:(是的,你是100%正确的,非规范化的想法是痛苦的,但是这种方法在读取/查询方面肯定是最有效的,我想这是NoSQL类型数据存储的最大好处,并确保在单独的MVP中没有大量重复数据。非常感谢!
select * from Event where user in (select friends from User where id = ?)
// Key<User> userKey = ...
User user = ofy.load.type(User.class).key(userKey).first.now;
List<Key<User>> friends = user.getFriends();
ofy.load.type(Event.class).filter("user in", friends).order("-eventTime")list();