我正在构建一个应用程序,用户可以通过回答一堆多项选择题来为自己创建配置文件。用户还可以通过指定这些问题的答案标准来搜索其他用户。
让我们说我们有9个问题q1 .. q9,每个问题有6个可能的答案(0到5)。这可以在用户配置文件中表示为:
class UserProfile(db.Model):
user = db.StringProperty(required=True)
q1 = db.IntegerProperty()
...
q9 = db.IntegerProperty()
现在,考虑用户想要为回答:
的用户运行查询我们可以写一个查询,例如:
q = UserProfile.all()
q.filter("q1 IN", [0, 1, 2])
q.filter("q2 IN", [1, 2, 5])
...
q.filter("q9 IN", [3, 4, 5])
不幸的是,这将产生近20,000个子查询(假设用户为每个过滤器指定了3个可能的答案),这远远大于允许的30个,更不用说其可怕的低效率了。
是否有设计模式可以有效地完成这项工作?
通过使用二进制编码(例如,[1,2,5] - > b100110 = 38)将每个过滤器表示为整数并存储每个用户答案,我可以设想将这些过滤器中的每一个转换为单个相等过滤器的方法在数据存储区中作为它将匹配的查询列表(例如,1 - > bxxxx1x - > [2,3,6,7,10,11,...,62,63])。然而,这看起来有些麻烦。
如果有人对实施提出更有效的建议,我将不胜感激。
更新(关于建议的二进制编码):
Nick Johnson对上面提到的二进制编码提出了一些有趣的担忧,因此我想更详细地澄清所提出的编码,以便让他和其他人能够对其优点和挑战进行明确的评估。
我认为一个具体的例子最有效。另外,我认为从查询机制开始也更直观。
继续上面的例子,让我们假设有9个问题,每个问题有6个可能的答案(0到5)。我们还定义每个查询将采用多个这些问题的过滤器的形式,以便与多个可能的答案进行匹配(如上所述)。我建议转换形式的每个查询" q2 IN [1,2,5]"使用二进制编码的相等滤波器,如果它是查询响应之一,则每个位位置为1,否则为0。例如," q2 IN [1,2,5]"将转换为" q2 == b100110"或" q2 == 38"。进一步应用此功能,上述复合查询将转换为以下多个相等过滤器:
启用" IN"过滤到" =="过滤器,我们需要事先确定哪些查询(以二进制编码形式)的配置文件响应将匹配。例如,如果用户选择2(在0到5之间)作为答案,则该响应将匹配其二进制编码在2位中具有1的任何查询,即bxxx1xx形式,其中x可以是0或1 .bxxx1xx定义的整数集是[b000100,b000101,b000110,b000111,b001100,b001101,...,b111100,b111101,b111110,b111111]或十进制形式:[4,5,6,7,12, 13,...,60,61,62,63],它是32个整数的列表。一般来说,这个"查询匹配集"将有2 ^(n-1)个元素用于对具有n个可能答案的问题的响应,因为二进制编码中的n个比特中的1个将固定为1,而其他的可以是0或1。
因此,如果我们有m个问题,每个问题都有n个可能的答案,那么存储这些"查询匹配集的每个实体的索引条目数"对于每个问题将是m x(2 ^(n-1))。如果我有:
因此,我同意对于任意大量的问题,这不是一种合适的方法,特别是如果问题的答案的可能数量也很大。但是,如果要编入索引的问题数量为10-15,并且可能的答案数不超过6,这似乎是可行的,至少对于大多数问题而言。
我将不超过10个需要编入索引的问题。他们中的大多数有3-5个可能的答案。有些人有6-7个可能的答案,所以我预计每个实体的索引条目少于300个(除非我对如何计算上述索引要求有误)。
我并不认为这是一个非常优雅的解决方案,但是:
我仍然会对以下问题有所了解:
答案 0 :(得分:2)
在您描述查询时,根本没有有效的方法来构建查询数据。唯一的方法是查询您认为最具限制性的标准,然后在内存中手动过滤剩余标准。
如果您告诉我们更多关于人们可能执行的具体查询类型以及原因,我们可能会提供更有效的具体建议。