【问题标题】:Django postgres full text search in reverse related models反向相关模型中的 Django postgres 全文搜索
【发布时间】:2017-03-17 05:52:03
【问题描述】:

我在我的 Django 项目中使用https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/search/。如何在搜索向量中添加反向相关模型?

class Container(models.Model):
    text = models.TextField()

class Item(models.Model):
    container = models.ForeignKey(Container)
    text = models.TextField()

如果相关 Item 包含搜索模式,我想在 ItemContainer 模型 text 字段中搜索并返回 QuerySetContainer 模型

【问题讨论】:

    标签: django postgresql


    【解决方案1】:

    就是这样:

    1. 确保您使用的是 django -gte 1.10
    2. 确保您的INSTALLED_APPS 上有'django.contrib.postgres',
    3. 按照您的问题创建两个模型。
    4. 只需进行迁移、迁移并使用一些数据填充模型:

    用数据填充模型:

    from fts.models import Item, Container    
    c=Container.objects.create( text = "hello" )  
    Item.objects.create( text ="Some word", container = c ) 
    
    1. 此时您已准备好进行查询:

    查询和检查结果:

    from django.contrib.postgres.search import SearchVector
    >>> ( Container
    ...       .objects
    ...       .annotate(search=SearchVector('text', 'item__text'),)
    ...       .filter(search='Some word')
    ...       .distinct()
    ...      )
    

    结果如预期:

    <QuerySet [<Container: Container object>]>
    
    1. 为了确保您的查询使用完整的搜索 postgres 功能正常工作,您可以打印底层 sql:

    询问底层SQL:

    >>> print ( Container
                .objects
                .annotate(search=SearchVector('text', 'item__text'),)
                .filter(search='Some word')
              ).query
    

    结果是:

    SELECT 
        "fts_container".
        "id", "fts_container".
        "text", 
        to_tsvector(COALESCE("fts_container"."text", ) 
                    || ' ' || 
                    COALESCE("fts_item"."text", )) AS "search"
    FROM            
        "fts_container"
    LEFT OUTER JOIN 
        "fts_item"
              ON("fts_container"."id" = "fts_item"."container_id") 
    WHERE to_tsvector(
            COALESCE("fts_container"."text", ) 
            || ' ' || 
            COALESCE("fts_item"."text", )
          )@@(plainto_tsquery(Some word)) = true
    

    实际操作:

    性能:

    我不知道当您混合来自多个表的字段时,postgres 是否能够利用索引的完整搜索功能。但是很容易检查它。创建全文索引和ANALYZE您的表后,您可以询问sql计划:

    fts=> EXPLAIN SELECT 
    fts->     "fts_container".
    fts->     "id", "fts_container".
    fts->     "text", 
    fts->     to_tsvector(COALESCE("fts_container"."text", '' ) 
    fts(>                 || ' ' || 
    fts(>                 COALESCE("fts_item"."text", '' )) AS "search"
    fts-> FROM            
    fts->     "fts_container"
    fts-> LEFT OUTER JOIN 
    fts->     "fts_item"
    fts->           ON("fts_container"."id" = "fts_item"."container_id") 
    fts-> WHERE to_tsvector(
    fts(>         COALESCE("fts_container"."text", '' ) 
    fts(>         || ' ' || 
    fts(>         COALESCE("fts_item"."text",'' )
    fts(>       )@@(plainto_tsquery('Some word')) = true
    fts-> ;
                                                                             QUERY PLAN                                                                          
    -------------------------------------------------------------------------------------------------------------------------------------------------------------
     Hash Right Join  (cost=1.04..2.15 rows=1 width=68)
       Hash Cond: (fts_item.container_id = fts_container.id)
       Filter: (to_tsvector(((COALESCE(fts_container.text, ''::text) || ' '::text) || COALESCE(fts_item.text, ''::text))) @@ plainto_tsquery('Some word'::text))
       ->  Seq Scan on fts_item  (cost=0.00..1.04 rows=4 width=36)
       ->  Hash  (cost=1.02..1.02 rows=2 width=36)
             ->  Seq Scan on fts_container  (cost=0.00..1.02 rows=2 width=36)
    (6 rows)
    

    【讨论】:

    • 我认为如果容器中有 item = models.ForeignKey(Item) 应该可以。但是在我的 sn-p 中,我在 Item 模型中有 Container 的外键,这会在 Container 中创建反向关系 item_set,因此 SearchVector 必须包含这些 item_set 条目。
    • 如果您要求某些东西,而 22K 的人向您建议一个答案,一个好主意是尝试它而不是说“我认为这行不通”。我在真实环境中逐步发布了答案。
    • o_O 哇,这个答案太棒了,我需要一些时间来了解它是如何工作的。感谢您的解决方案!
    猜你喜欢
    • 1970-01-01
    • 2019-05-16
    • 2011-04-01
    • 1970-01-01
    • 2017-03-31
    • 2012-11-08
    • 1970-01-01
    • 2020-05-07
    • 2010-11-11
    相关资源
    最近更新 更多