GAE 数据存储不等式过滤两个属性建议
GAE datastore inequality filter two properties advice
我有一个场景,我需要在数据存储中查询在过去 X 分钟内活跃的一些随机用户。
我的每个用户实体都有一个名为 'random' 的 属性。当我想找到一些随机用户时,我会生成一个随机最小值和最大值,并使用它们来查询数据存储区中的用户随机 属性.
这是我目前得到的:
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;
}
我现在只需要最近活跃的用户。
每个用户实体也有一个 'last active' 属性,我想将其包含在查询中,例如上次活动 > 30 分钟前。
这意味着要对两个属性进行不等式过滤,我做不到。
最有效的方法是什么?
我可以让所有用户实体在最后 X 分钟内处于活动状态,然后随机选择一些。我可以让我的代码保持原样,并在将它们添加到非重复实体列表之前检查最后一个活动状态,但这可能涉及对数据存储的大量调用。
有没有其他方法可以仅使用查询来完成此操作?
鉴于上述评论,这里是一种方法。
假设您有一个存储日期时间戳的 "last active" 属性,然后您可以执行仅键查询,其中最后一个活动 datetime_stamp > "a datetime stamp of interest" .
在检索密钥时对结果集执行随机选择,然后使用 get 操作显式获取密钥。这将限制小型操作和获取的成本。
然后我会考虑在内存缓存中缓存这组密钥,并定义一个有效期限,这样如果您在下一个指定期限内需要另一个随机选择而不是重新查询,您可以重新使用这组密钥, 2秒后。鉴于随机选择,准确性似乎不太重要。
如果采用缓存策略,则需要处理缓存过期和刷新缓存的问题。
这里的一个潜在问题是 运行 dogpile 效应,其中多个请求都无法同时检索缓存,并且每个处理程序都开始构建缓存。在轻负载系统中,这可能不是问题,在具有大量 activity 的重负载系统中,您可能希望通过任务保持缓存处于活动状态。 - 只是想一想。
我有一个场景,我需要在数据存储中查询在过去 X 分钟内活跃的一些随机用户。
我的每个用户实体都有一个名为 'random' 的 属性。当我想找到一些随机用户时,我会生成一个随机最小值和最大值,并使用它们来查询数据存储区中的用户随机 属性.
这是我目前得到的:
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;
}
我现在只需要最近活跃的用户。
每个用户实体也有一个 'last active' 属性,我想将其包含在查询中,例如上次活动 > 30 分钟前。
这意味着要对两个属性进行不等式过滤,我做不到。
最有效的方法是什么?
我可以让所有用户实体在最后 X 分钟内处于活动状态,然后随机选择一些。我可以让我的代码保持原样,并在将它们添加到非重复实体列表之前检查最后一个活动状态,但这可能涉及对数据存储的大量调用。
有没有其他方法可以仅使用查询来完成此操作?
鉴于上述评论,这里是一种方法。
假设您有一个存储日期时间戳的 "last active" 属性,然后您可以执行仅键查询,其中最后一个活动 datetime_stamp > "a datetime stamp of interest" .
在检索密钥时对结果集执行随机选择,然后使用 get 操作显式获取密钥。这将限制小型操作和获取的成本。
然后我会考虑在内存缓存中缓存这组密钥,并定义一个有效期限,这样如果您在下一个指定期限内需要另一个随机选择而不是重新查询,您可以重新使用这组密钥, 2秒后。鉴于随机选择,准确性似乎不太重要。
如果采用缓存策略,则需要处理缓存过期和刷新缓存的问题。
这里的一个潜在问题是 运行 dogpile 效应,其中多个请求都无法同时检索缓存,并且每个处理程序都开始构建缓存。在轻负载系统中,这可能不是问题,在具有大量 activity 的重负载系统中,您可能希望通过任务保持缓存处于活动状态。 - 只是想一想。