2010-01-05 46 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