2010-01-05 43 views
3

这将是一个“漫长的”。我尽可能地包含尽可能多的代码和解释......如果有必要,我不会抛出代码。在django-query中实现逻辑分析器

我想在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。我用一个疯狂的字符串-EVAL黑客创建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分钟才能完成所有样本。所以我每晚计算篮子,然后在白天冻结它们。我担心,随着我开始策划更多的篮子,样品和标签会变得很糟糕。

有什么建议吗?

+0

我也尝试过将“()”类型的查询分解为更长的,但没有parens的等价版本,但还没有能够使这些工作。 – JudoWill 2010-01-05 05:05:46

回答

1

首先,为了提高性能,可能有助于在标记名称字段上添加索引,因为您正在将它用于查询。所以,加db_index =真将您的列:

class Tag(models.Model): 
    name = models.CharField(max_length = 255, db_index=True) 
    samples = models.ManyToManyField(Sample) 

其次,分析用户的查询我会建议使用一些好的基于Python的解析器,如PyParsingPLY之一。这些看起来似乎很吓人,但实际上并不困难,特别是使用简单的语法,比如你的。

如果这些对你来说太过分了,那么试着用Fredrik的指南Simple Top-Down Parsing in Python来滚动你自己。

+0

其他注意事项:您需要重置您的数据库以查看由syncdb发现的db_index。如果您无法重置,则需要手动将索引手动添加到数据库,或者使用像South(http://south.aeracode.org/)这样的迁移工具。 – 2010-01-05 10:11:19

+0

谢谢范...我想我可以用他们的例子来简单的数学表达式“http://pyparsing.wikispaces.com/file/view/fourFn.py”。只需用queryset操作替换'math.operations',然后让它处理嵌套等。 – JudoWill 2010-01-05 15:31:13