组合多个 ndb 不等式查询的结果
Combining results of multiple ndb inequality queries
NDB 数据存储禁止对不同属性进行多个不等式查询。为了解决这个问题,我认为解决方案可能是合并多个独立查询的结果。我发现 this 2011 question 推荐我不熟悉的 geohashing。所以,也许今天有更好的解决方案。
考虑这两个查询:
q1 = User.query(User.age < 18).fetch()
q2 = User.query(User.city != 'New York City').fetch()
我尝试这样加入他们:
results = set(q1).intersection(q2)
然而,我遇到了TypeError: Model is not immutable
。
我的问题:
- 有没有更好的方法来处理不同属性的多个不等式过滤器?
- 如果没有,我该如何解决上面的
TypeError
?
感谢您的帮助。
如果您可以重构 User
模型,则可以添加更多属性以使查询更简单。例如,如果您查询相同的年龄范围,则创建一个编码范围的 属性:
age_range = ndb.IntegerProperty() # 0 = 0-17, 1 = 18-29, 2 = 30-39, etc.
那么你可以拥有:
q1 = User.query(User.age_range == 0).query(User.city != 'New York City').fetch()
如果你的数据集足够小,你可以使用@TimHoffman 的方法:
q1 = User.query(User.age < 18).fetch(keys_only=True)
q2 = User.query(User.city != 'New York City').fetch(keys_only=True)
results = ndb.get_multi(set(q1).intersection(q2))
一种更重量级的方法,可以扩展到大数据集,是 MapReduce 库。您可以放入多个过滤器来减少数据集。
我遇到了类似的问题。我的查询是:
@classmethod:
def getUnReadMessages(cls, user, date)
return cls.query(ndb.AND(cls.created <= date,
cls.receiver_key == user.key,
cls.status != READ))
但是appengine不让我做。所以我解决了将一个不等式更改为:
@classmethod:
def getUnReadMessages(cls, user, date)
return cls.query(ndb.AND(cls.created <= date,
cls.receiver_key == user.key,
ndb.OR(cls.status == SEND,
cls.status == RECEIVED)))
问题解决了!希望对你有帮助。
有两种选择:
更改您的数据模型
添加更多属性或调整当前属性,以便您可以根据数据存储的限制查询对象。这可能意味着对连续变量进行分类。
找到解决方法
您可以先进行最重要的查询,然后手动过滤结果。请牢记以下注意事项:
- 您可以使用projection来提高查询效率。
- 使结果可迭代 (iter)。
- 使用 get_multi 键列表。
您的代码可能如下所示:
query_iter = User.query(User.age < 18).iter(projection=[User.city])
query_keys = [u.key() for u in query_iter if u.city != 'New York City']
query = ndb.get_multi(query_keys)
或
query = [u for u in User.query(User.age < 18).fetch() if u.city != 'New York City']
NDB 数据存储禁止对不同属性进行多个不等式查询。为了解决这个问题,我认为解决方案可能是合并多个独立查询的结果。我发现 this 2011 question 推荐我不熟悉的 geohashing。所以,也许今天有更好的解决方案。
考虑这两个查询:
q1 = User.query(User.age < 18).fetch()
q2 = User.query(User.city != 'New York City').fetch()
我尝试这样加入他们:
results = set(q1).intersection(q2)
然而,我遇到了TypeError: Model is not immutable
。
我的问题:
- 有没有更好的方法来处理不同属性的多个不等式过滤器?
- 如果没有,我该如何解决上面的
TypeError
?
感谢您的帮助。
如果您可以重构 User
模型,则可以添加更多属性以使查询更简单。例如,如果您查询相同的年龄范围,则创建一个编码范围的 属性:
age_range = ndb.IntegerProperty() # 0 = 0-17, 1 = 18-29, 2 = 30-39, etc.
那么你可以拥有:
q1 = User.query(User.age_range == 0).query(User.city != 'New York City').fetch()
如果你的数据集足够小,你可以使用@TimHoffman 的方法:
q1 = User.query(User.age < 18).fetch(keys_only=True)
q2 = User.query(User.city != 'New York City').fetch(keys_only=True)
results = ndb.get_multi(set(q1).intersection(q2))
一种更重量级的方法,可以扩展到大数据集,是 MapReduce 库。您可以放入多个过滤器来减少数据集。
我遇到了类似的问题。我的查询是:
@classmethod:
def getUnReadMessages(cls, user, date)
return cls.query(ndb.AND(cls.created <= date,
cls.receiver_key == user.key,
cls.status != READ))
但是appengine不让我做。所以我解决了将一个不等式更改为:
@classmethod:
def getUnReadMessages(cls, user, date)
return cls.query(ndb.AND(cls.created <= date,
cls.receiver_key == user.key,
ndb.OR(cls.status == SEND,
cls.status == RECEIVED)))
问题解决了!希望对你有帮助。
有两种选择:
更改您的数据模型
添加更多属性或调整当前属性,以便您可以根据数据存储的限制查询对象。这可能意味着对连续变量进行分类。
找到解决方法
您可以先进行最重要的查询,然后手动过滤结果。请牢记以下注意事项:
- 您可以使用projection来提高查询效率。
- 使结果可迭代 (iter)。
- 使用 get_multi 键列表。
您的代码可能如下所示:
query_iter = User.query(User.age < 18).iter(projection=[User.city])
query_keys = [u.key() for u in query_iter if u.city != 'New York City']
query = ndb.get_multi(query_keys)
或
query = [u for u in User.query(User.age < 18).fetch() if u.city != 'New York City']