【发布时间】:2016-05-26 05:00:18
【问题描述】:
我有一个场景,我需要在数据存储中查询一些在过去 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;
}
我现在只需要最近活跃的用户。
每个用户实体还有一个“上次活动”属性,我想将其包含在查询中,例如最后一次活动 > 30 分钟前。
这意味着对两个属性使用不等式过滤器,我不能这样做。
最有效的方法是什么?
我可以在最后 X 分钟内激活所有用户实体,然后随机选择一些。我可以保留我的代码,并在将它们添加到非重复实体列表之前检查最后一个活动,但这可能涉及对数据存储的大量调用。
是否有其他方法可以仅使用查询来做到这一点?
【问题讨论】:
-
X 在你的随机分钟内有多固定,你感兴趣的时间是几分钟,10 分钟 50 分钟?
-
@TimHoffman 分钟值不会是随机的,它将是一个介于 10 到 30 之间的常数值
-
一旦你有一个最近活跃的 n 个用户列表,你可以从列表中随机挑选一些显示在内存中。在数据库中存储随机值......我们只是说它可能不是所有想法中最好的。随机值的索引和按这些排序只是浪费钱恕我直言。
-
虽然一个键只查询最近有活动的用户,比如最近 50 个,然后随机选择一个键然后得到那个单一的实体不会太贵。此外,您可以将密钥缓存在 memcache 中一小段时间,然后重复使用以随机选择,直到缓存过期。
-
@Simon 请将链接添加到您所指的答案中,以便我可以责骂某人 ;-)。蒂姆的最后评论可能是最好的解决方案。另请注意,数据库中的随机值不会给您预期的随机结果。用户总是以相同的顺序排序,所以如果有一个用户的随机值非常低,他总是会主导你最近的活动(或其他)列表。蒂姆:我可以建议你根据你的评论来回答吗?
标签: google-app-engine google-cloud-datastore