0

我有一个活动表,其中显示哪些用户关注谁。(fromUsertoUser)我正在构建一个排行榜,以查看在追随者中发布的评分最高的人。

所以我创建了这个查询:

ParseQuery<ParseObject> queryActivityFollowing = new ParseQuery<>("Activity");
queryActivityFollowing.whereEqualTo("type", "follow");
queryActivityFollowing.whereEqualTo("fromUser", ParseUser.getCurrentUser());
queryActivityFollowing.setLimit(500);

// innerQuery, only get Users posted by the users I follow
ParseQuery<ParseUser> queryUserFollowing = ParseUser.getQuery();
queryUserFollowing.whereMatchesQuery("toUser", queryActivityFollowing);

// querySelf
ParseQuery<ParseUser> querySelf = ParseUser.getQuery();
querySelf.whereEqualTo("objectId", ParseUser.getCurrentUser().getObjectId());

List<ParseQuery<ParseUser>> queries = new ArrayList<>();
queries.add(queryUserFollowing);
queries.add(querySelf);

query = ParseQuery.or(queries);
query.orderByDescending("rating_count");
query.setLimit(20);

但不知何故,它超时并且从不显示结果。我的查询是否效率低下?

谢谢!

编辑: 数据描述: Activity是一个有 3 列的类,fromUser, toUser, typefromUser并且toUser是指向_User类的指针,type是一个字符串

在 中_User,我有经典属性和一个名为 的整数rating_count,它是 orderBy 标准(上面更新了代码)。

实际上,我认为查询不会超时,而只是返回 0 个结果。我关注我的一些用户,所以这绝对不是预期的输出。

4

2 回答 2

1

这是一个艰难的问题,因为 parse 的查询仅最低限度地支持这种事情。我能提供的最好的想法是这个:

  1. 对 Activity 表的一次查询whereEqualTo("type", "follow")whereEqualTo("fromUser", ParseUser.getCurrentUser())
  2. 没有 queryUserFollowing,没有 querySelf。这些都是不必要的。这也使您从Parse.Query.or().
  3. setLimit(1000)将在下面解释原因
  4. include("toUser")
  5. 完成后,遍历结果,最大化result.get("toUser").getInt("rating_count")因为结果将是 Activity 的实例,并且您将急切地获取它们的相关 toUsers。

此方案比您编写的方案更简单,并且可以完成工作。但是,可能一个主要问题是它会丢失超过 1000 个关注者的用户的数据。让我知道这是否是一个问题,我可以提出一个更复杂的答案。一个小缺点是您将被迫自己在内存中进行搜索(可能是排序)以找到最大的 rating_count。

编辑- 对于 > 1k 的追随者,您被困在多次调用查询中,将 设置为skip上一个查询中收到的记录数,将结果收集到一个大数组中。

您关于传输如此多数据的观点得到了很好的理解,您可以通过将所有这些都放入云功能中,在云中进行内存工作并仅返回客户端需要的记录来最大限度地减少网络使用。(这种方法还有一个额外的好处,就是用 javascript 编码,我比 java 说得更流利,所以我可以对代码更加规范)。

编辑 2 - 在云代码中执行此操作的好处是,将网络流量减少到只有那些具有最高评级的用户(例如 20 个)。它不能解决我之前指出的其他问题。这是我在云中的操作方式...

var _ = require('underscore');

Parse.Cloud.define("topFollowers", function(request, response) {
    var user = new Parse.User({id:request.params.userId});
    topFollowers(user, 20).then(function(result) {
        response.success(result);
    }, function(error) {
        response.error(error);
    });
});

// return the top n users who are the top-rated followers of the passed user
function topFollowers(user, n) {
    var query = new Parse.Query("Activity");
    query.equalTo("type", "follow");
    query.equalTo("fromUser", user);
    query.include("toUser");
    return runQuery(query).then(function(results) {
        var allFollowers = _.map(results, function(result) { return result.get("toUser"); });
        var sortedFollowers = _.sortBy(allFollowers, function(user) { return user.get("rating_count"); });
        return _.first(sortedFollowers, n);
    });
}

// run and rerun a query using skip until all results are gathered in results array
function runQuery(query, results) {
    results = results || [];
    query.skip(results.length);
    return query.find().then(function(nextResults) {
        results = results.concat(nextResults);
        return (nextResults.length)? runQuery(query, results) : results;
    });
}

注意 - 我没有对此进行测试,但在生产中也有类似的东西。

于 2015-05-25T19:31:56.050 回答
1

如果您准备更改数据模型,那么有一个解决方案可以满足您的需求,并带来一些附带好处。考虑一个系统,其中 User 类仅与应用程序和真人之间的关系有关。用户彼此之间的公共面孔由一个新类(称为 PublicUser 或 Persona)呈现。

在这个PublicUser类中,你有一个指向user拥有它的 s 的指针,以及一个指向其他s的指针数组。该类还包含该属性。现在OP中的查询很简单:PublicUserfollowingrating

  1. 查询 PublicUser whereKey "following" 等于 currentUser
  2. 按等级排序,限制为 20 或您希望限制的任何数量

就是这样。该方案的另一个好处是访问控制。系统理解,PublicUser 中的任何内容对其他 PublicUser 都是可读的,并且关于 __User 的所有内容都保存在该个人和应用程序之间。

于 2015-05-25T20:55:27.427 回答