有效搜索Django中的ForeignKeys树

时间:2009-09-22 20:08:25

标签: django orm

我使用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字段(即不仅仅是'name')。

我想要做的是有一个搜索功能,以便有一个字符串 提供的将返回任何匹配Person对象的Person 本身,或任何子节点中的字段。 IOW,如果“击败它”就是 字符串,以及与相关联的相关联的歌曲的名称 人匹配,该人将被退回。

到目前为止我所做的是以下内容:

对于任何叶节点,请使用具有搜索方法的Manager对象 类似的东西:

return Song.objects.filter(name__icontains=search_string)

然后对于根节点(Person)和任何内部节点,还有一个 具有search()方法的Manager对象,如下所示:

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()方法,可以手动搜索 通过一切,但a)看起来非常混乱(虽然可能更多 有效的)和b)能够搜索单个节点会很高兴 任意。

所有这一切都说,什么是更有效的获取方法 我想在哪里而不是我的骨头方法?

4 个答案:

答案 0 :(得分:2)

将搜索功能外包给WooshSphinx等专用工具可能会更好。两个搜索框架的项目都将它们与Django(分别为django-haystackdjango-sphinx)集成在一起。与具有许多连接和子查询的复杂SQL查询相比,您将获得更好的性能。

答案 1 :(得分:2)

好吧,如果您不想设置像whoosh这样的搜索引擎,那么您可以使用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 :(得分:1)

Django Solr是另一种选择。

答案 3 :(得分:1)

我认为你对基本的ORM做的任何事情都不会真正有效,你基本上会在不同的模型上运行一系列的filter()查询,并且有很多JOIN。< / p>

如果您的目标是高性能,长期解决方案,最好的办法是在内存中创建一个对象存储库。我没有看到基本SQL中的任何方法可以使这些查询有效,特别是如果你正在使用大量的行。

为包含所有Person和Book / Album数据的子对象(章节,歌曲等)创建非规范化表可能是一个潜在的中期解决方案,这将需要一些可能不属于您的一些奇特的SQL步法Django Core。