解析:追踪者的复合查询超时

时间:2015-05-25 18:35:31

标签: javascript android parse-platform inner-query

我有一个活动表,说明哪些用户关注谁。 (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列的类fromUsertoUsertypefromUsertoUser是指向_User类的指针,type是一个字符串

_User中,我有经典属性和一个名为rating_count的整数,orderBy条件(上面的更新代码)。

实际上,我认为查询没有超时,但只返回0结果。我关注了一些用户,所以它绝对不是预期的输出。

2 个答案:

答案 0 :(得分:1)

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

  1. 有关活动表whereEqualTo("type", "follow")whereEqualTo("fromUser", ParseUser.getCurrentUser())
  2. 的一个查询
  3. 没有queryUserFollowing,没有querySelf。这些是不必要的。这也使您免于Parse.Query.or()
  4. setLimit(1000)将在
  5. 下解释原因
  6. include("toUser")
  7. 完成后,遍历结果,最大化result.get("toUser").getInt("rating_count"),因为结果将是Activity的实例,并且您将急切地获取他们的相关用户。
  8. 此方案比您编码的方案简单,并且可以完成工作。然而,可能的主要问题是它将错过用于&gt;的用户的数据。 1000粉丝。如果这是一个问题,让我知道,我可以建议一个更复杂的答案。一个小缺点是你将被迫在内存中进行搜索(可能是一种)以找到最大rating_count。

    编辑 - 对于&gt; 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;
        });
    }
    

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

答案 1 :(得分:1)

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

在这个PublicUser类中,你拥有一个指针到拥有它的user,一个一个指针数组到其他{ {1}}这个人是谁PublicUser。该类还包含following属性。现在OP中的查询很简单:

  1. 查询PublicUser whereKey“follow”等于currentUser
  2. 按评级排序,限制为20或您希望限制的任何数字
  3. 就是这样。该方案的另一个好处是访问控制。系统可以理解,PublicUser中的任何内容都可以被其他PublicUser读取,而__User的所有内容都保存在该个人和应用之间。