使用PostgreSQL的Django全文搜索,跨多种不同的模型

pes8fvy9  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(2)|浏览(139)

我需要在多个不同的模型上执行FTS。我想在搜索结果中获得任何型号。
我想按排名排序结果,以获得最相关的结果。我可以一个接一个地运行搜索,但不确定如何合并结果,尤其是保留排名相关性。
这里是模型,它是一个例子,从使查询手册页。

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()
iklwldmw

iklwldmw1#

你可以用类似这样的方法将多个查询集合并成一个。

from itertools import chain

blogs = Blog.objects.filter(...)
authors = Author.objects.filter(...)
entries = Entry.objects.search(...)

chain = chain(blog_results, lesson_results, profile_results)
qs = sorted(chain, key=lambda instance: instance.pk, reverse=True)
uqxowvwt

uqxowvwt2#

使用QuerySet.union操作符,只要查询的结果SELECT使用相同的类型,就可以合并来自不同模型的QuerySets。
这篇博客文章的作者有一个使用SearchRankSearchQuery的简洁示例。请注意,这在每个模型('pk', 'type', 'rank')上使用相同的值,以便.union()工作。type注解通知返回的模型
这允许你在数据库端而不是Django中进行排序,限制甚至进一步过滤。
来自文章的查询:

from django.contrib.postgres.search import SearchRank, SearchQuery  # not in the article, but implied

query = SearchQuery('django')
rank_annotation = SearchRank(F('search_document'), query)

qs = Blogmark.objects.annotate(
    rank=rank_annotation,
    type=models.Value('blogmark', output_field=models.CharField())
).filter(
    search_document=query
).values('pk', 'type', 'rank').union(
    Entry.objects.annotate(
        rank=rank_annotation,
        type=models.Value('entry', output_field=models.CharField())
    ).filter(
        search_document=query
    ).values('pk', 'type', 'rank'),
    Quotation.objects.annotate(
        rank=rank_annotation,
        type=models.Value('quotation', output_field=models.CharField())
    ).filter(
        search_document=query
    ).values('pk', 'type', 'rank'),
).order_by('-rank')[:5]

文章的结果:

<QuerySet [
    {'pk': 186, 'type': u'quotation', 'rank': 0.875179},
    {'pk': 134, 'type': u'quotation', 'rank': 0.842655},
    {'pk': 1591, 'type': u'entry', 'rank': 0.804502},
    {'pk': 5093, 'type': u'blogmark', 'rank': 0.788616},
    {'pk': 2598, 'type': u'blogmark', 'rank': 0.786928}
]>

相关问题