这将是一个“长篇”。我包含尽可能多的代码和解释......如果有必要,我不会放弃代码。
我正在尝试在 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 分钟才能完成所有样本。所以我每晚计算篮子,然后在白天把它们冷冻起来。我担心当我开始策划更多的篮子、样本和标签时,这将无法扩展。有什么建议么?
最佳答案
首先,为了提高性能,在标签名称字段上添加索引可能会有所帮助,因为您正在使用它进行查询。所以,添加 db_index=真到你的专栏:
class Tag(models.Model):
name = models.CharField(max_length = 255, db_index=True)
samples = models.ManyToManyField(Sample)
其次,为了解析用户查询,我建议使用几个好的基于 Python 的解析器之一,例如 PyParsing。或 PLY .这些乍一看可能令人生畏,但实际上并不难,尤其是像您这样的简单语法。
如果这些对您来说太多了,那么请尝试使用 Fredrik 的指南 Simple Top-Down Parsing in Python 自己动手。 .
关于django - 在 django-query 中实现逻辑解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2004190/