GAE数据存储不等式过滤两个属性建议

时间:2016-02-15 10:20:17

标签: google-app-engine google-cloud-datastore

我有一个场景,我需要查询数据存储区中一些在过去X分钟内处于活动状态的随机用户。

我的每个用户实体都有一个名为“随机”的属性。当我想找到一些随机用户时,我会生成一个随机的最小值和最大值,并使用它们根据用户随机属性查询数据存储区。

这是我到目前为止所得到的:

public static List<Entity> getRandomUsers(Key filterKey, String gender, String language, int maxResults) {
    ArrayList<Entity> nonDuplicateEntities = new ArrayList<>();

    HashSet<Entity> hashSet = new HashSet<>();
    int attempts = 0;
    while (nonDuplicateEntities.size() < maxResults) {
        attempts++;
        if (attempts >= 10) {
            return nonDuplicateEntities;
        }

        double ran1 = Math.random();
        double ran2 = Math.random();

        Filter randomMinFilter = new Query.FilterPredicate(Constants.KEY_RANDOM, Query.FilterOperator.GREATER_THAN_OR_EQUAL, Math.min(ran1, ran2));
        Filter randomMaxFilter = new Query.FilterPredicate(Constants.KEY_RANDOM, Query.FilterOperator.LESS_THAN_OR_EQUAL, Math.max(ran1, ran2));
        Filter languageFilter = new Query.FilterPredicate(Constants.KEY_LANGUAGE, Query.FilterOperator.EQUAL, language);

        Filter randomRangeFilter;
        if (gender == null || gender.equals(Constants.GENDER_ANY)) {
            randomRangeFilter = Query.CompositeFilterOperator.and(randomMinFilter, randomMaxFilter, languageFilter);
        } else {
            Filter genderFilter = new Query.FilterPredicate(Constants.KEY_GENDER, Query.FilterOperator.EQUAL, gender);
            randomRangeFilter = Query.CompositeFilterOperator.and(randomMinFilter, randomMaxFilter, genderFilter, languageFilter);
        }

        Query q = new Query(Constants.KEY_USER_CLASS).setFilter(randomRangeFilter);

        PreparedQuery pq = DatastoreServiceFactory.getDatastoreService().prepare(q);

        List<Entity> entities = pq.asList(FetchOptions.Builder.withLimit(maxResults - nonDuplicateEntities.size()));
        for (Entity entity : entities) {
            if (filterKey.equals(entity.getKey())) {
                continue;
            }
            if (hashSet.add(entity)) {
                nonDuplicateEntities.add(entity);
            }
            if (nonDuplicateEntities.size() == maxResults) {
                return nonDuplicateEntities;
            }
        }
    }

    return nonDuplicateEntities;
}

我现在只需要最近活跃的用户。

每个用户实体还具有“最后有效”属性,我想在查询中包含该属性,例如最后活跃&gt; 30分钟前。

这意味着对两个属性进行不等式过滤,这是我无法做到的。

最有效的方法是什么?

我可以让所有用户实体在最后X分钟内处于活动状态,然后选择一些随机的实体。我可以保留我的代码,并在将它们添加到非重复实体列表之前检查最后一个活动,但这可能涉及对数据存储区的大量调用。

还有其他方法可以使用查询吗?

1 个答案:

答案 0 :(得分:3)

鉴于以上所述的评论是一种方法。

假设您具有存储日期时间戳的“最后活动”属性,则可以执行仅密钥查询,其中最后一个活动的datetime_stamp&gt; “感兴趣的日期时间戳”。

在检索密钥时,对结果集执行随机选择,然后使用get操作显式获取密钥。这将限制小操作和获取的成本。

我会考虑在memcache中缓存这组密钥,并定义到期时间,因此如果您需要在下一个指定期间进行另一个随机选择而不是重新查询,则可以重新使用该组密钥,2秒后来。考虑到随机选择,准确性似乎并不太重要。

如果您采用缓存策略,则必须处理缓存过期并刷新缓存。

这里的一个潜在问题是陷阱效应,其中多个请求都无法同时检索缓存,并且每个处理程序都开始构建缓存。在负载较轻的系统中,这可能不是问题,在具有大量活动的负载很重的系统中,您可能希望通过任务保持缓存处于活动状态。 - 只需要考虑一下。