我在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
包含搜索,我想在Container
和text
个模型QuerySet
字段中进行搜索,并返回Container
个Item
个模型图案
答案 0 :(得分:3)
这是方式:
'django.contrib.postgres',
INSTALLED_APPS
使用数据填充模型:
from fts.models import Item, Container
c=Container.objects.create( text = "hello" )
Item.objects.create( text ="Some word", container = c )
查询和检查结果:
from django.contrib.postgres.search import SearchVector
>>> ( Container
... .objects
... .annotate(search=SearchVector('text', 'item__text'),)
... .filter(search='Some word')
... .distinct()
... )
预期结果:
<QuerySet [<Container: Container object>]>
要求底层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)