这将是一个“长篇”。我包含尽可能多的代码和解释......如果有必要,我不会放弃代码。
我正在尝试在 django 查询系统中实现逻辑解析器。用户可以在其中针对应用于样本的标签提供复杂的查询。这本质上是科学样本库的一部分,用户可以在其中应用定义的标签(组织类型、研究的疾病等)。然后,他们可以创建由对这些标签的逻辑查询定义的样本的持久“篮子”。
#models.py
class Sample(models.Model):
name = models.CharField(max_length = 255)
class Tag(models.Model):
name = models.CharField(max_length = 255)
samples = models.ManyToManyField(Sample)
A quick example:
#example data:
Sample1 has TagA, TagB, TagC
Sample2 has TagB, TagC, TagD
Sample3 has TagA, TagC, TagD
Sample4 has TagB
#example query:
'TagB AND TagC AND NOT TagD'
将返回 Sample1。我使用了一个疯狂的 string-eval hack 来创建一组Q()
对象:
def MakeQObject(expression):
"""
Takes an expression and uses a crazy string-eval hack to make the qobjects.
"""
log_set = {'AND':'&','OR':'|','NOT':'~'}
exp_f = []
parts = expression.split()
#if there is a ) or ( then we can't use this shortcut
if '(' in parts or ')' in parts:
return None
for exp in parts:
if exp in log_set:
exp_f.append(log_set[exp])
else:
exp_f.append("Q(tags__name__iexact = '%s')" % exp)
st = ' '.join(exp_f)
qobj = eval(st)
return qobj
但是,这在任何需要复杂的操作顺序或按 () 分组的情况下都会失败。给定相同的示例数据,查询:(TagA OR TagB) AND NOT TagD
应该返回 Sample1、Sample4 但不返回。我已经实现了一个“一次一个”函数,它可以获取一个 Sample 对象并执行查询。但是,在我的实际数据库中,我有 ~40,000 个样本和 ~400 个标签(每个样本约 ~7 个),迭代技术需要 ~4 分钟才能完成所有样本。所以我每晚计算篮子,然后在白天把它们冷冻起来。我担心当我开始策划更多的篮子、样本和标签时,这将无法扩展。
有什么建议么?