Это будет "длинный". Я включаю как можно больше кода и объяснений ... Я не стесняюсь выбрасывать код, если это необходимо.
Я пытаюсь реализовать логический парсер в системе запросов 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. Я использую сумасшедший взлом строки для создания набора 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 и выполнить запрос. Тем не менее, в моей фактической базе данных у меня есть ~ 40000 сэмплов и ~ 400 тэгов (примерно ~ 7 на сэмпл), и итеративный метод занимает ~ 4 минуты для завершения на всех сэмплах. Поэтому я подсчитываю корзины по ночам, а затем просто замораживаю их в течение дня. Я беспокоюсь о том, что когда я начну выкапывать больше корзин, образцов и меток, это будет плохо масштабироваться.
Есть предложения?