Эффективный поиск по дереву ForeignKeys в Django - PullRequest
1 голос
/ 23 сентября 2009

У меня есть древовидная структура, созданная из моделей с использованием ForeignKey связей. Как пример:

Model Person:  
   name = CharField  

Model Book:  
   name = CharField  
   author = FK(Person)  

Model Movie:  
   name = CharField  
   director = FK(Person)  

Model Album:  
   name = CharField  
   director = FK(Person)  

Model Chapter:  
   name = CharField  
   book = FK(Book)  

Model Scene:  
   name = CharField  
   movie = FK(Movie)  

Model Song:  
   name = CharField  
   album = FK(Album)  

Предостережение в том, что реальная структура глубже и шире, и узел может иметь несколько не-FK полей (т. е. не просто «имя»).

Что я хотел бы сделать, так это иметь функцию поиска, в которой есть строка предоставляется, который будет возвращать любого человека, который соответствует объекту Person сам, или поле в любом из дочерних узлов. IOW, если «бить это» строка и название песни, связанной с альбомом, связанным с человек совпадает, человек будет возвращен.

На данный момент я сделал следующее:

Для любого конечного узла есть объект Manager с методом поиска, который делает что-то вроде:

return Song.objects.filter(name__icontains=search_string)

Тогда для корневого узла (Person) и любых внутренних узлов также существует Объект менеджера с методом search (), который выглядит примерно так:

class AlbumManager(models.Model):  
    def search(self, search_string):  
        from_songs = Album.objects.filter(song__in=Song.objects.search(search_string))  
        return Album.objects.filter(name__icontains=search_string)|from_songs  

Как вы можете себе представить, как только вы доберетесь до корневого узла, это высвобождает огромное количество запросов и действительно неэффективно. Я бы хорошенькая Удивлен, если не было лучшего способа сделать это ... одна идея просто есть один метод search () в верхней части дерева, который выполняет поиск вручную через все, но а) это выглядит очень грязно (хотя, вероятно, больше эффективный) и б) было бы неплохо иметь возможность поиска отдельных узлов произвольно.

Итак, со всем сказанным, что было бы более эффективным методом получения где я хочу быть вместо моего метода тупица здесь?

Ответы [ 4 ]

2 голосов
/ 23 сентября 2009

Что ж, если вы не хотите настраивать поисковую систему, например, свист, тогда вы можете использовать Q

http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects

Это будет включать в себя жесткое кодирование полей, а не просто просмотр всех их.

>>> q = Q()
>>> q = q | Q( fk__fk__field__icontains = searchTerm )
>>> q = q | ...
...
>>> qs = Model.objects.filter(q)
2 голосов
/ 23 сентября 2009

Возможно, было бы лучше передать функции поиска стороннему инструменту, например Woosh или Sphinx . Существуют проекты для обеих поисковых систем, которые интегрируют их с Django ( django-haystack и django-sphinx , соответственно). Вы получите гораздо лучшую производительность, чем со сложными SQL-запросами со многими объединениями и подзапросами.

1 голос
/ 23 сентября 2009

Я не думаю, что что-то, что вы можете сделать с базовым ORM, будет действительно эффективным, вы в основном будете выполнять серию запросов filter () на разных моделях с адским множеством JOIN.

Если вы стремитесь к высокопроизводительным долгосрочным решениям, лучше всего создать хранилище объектов в памяти. Я не вижу никакого способа в базовом SQL, чтобы вы могли сделать эти запросы эффективными, особенно если вы работаете с кучей строк.

Создание денормализованной таблицы для ваших дочерних объектов (глава, песня и т. Д.), Которая содержит все ваши данные о персоне и книге / альбоме, может быть потенциальным среднесрочным решением, и для этого потребуется некоторая сложная работа с SQL, которая, вероятно, не является частью ядра Джанго.

1 голос
/ 23 сентября 2009

Django Solr является еще одним вариантом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...