這是這樣的:
- 確保你使用django -gte 1.10
- 確保您的
'django.contrib.postgres',
在您的INSTALLED_APPS
- 在你的問題中創建你的兩個模型。
- 只是makemigrations,一些數據遷移和填充模型:數據
填充型號:
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>]>
- 只是要確保您的查詢使用全搜索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
在行動:
![django and postgres fts](https://i.stack.imgur.com/AOMHm.png)
性能:
我不知道是否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)
我覺得如果你有'''項目= models.ForeignKey(項目)''集裝箱'應該工作。但在我的片段中,我在Item模型中有Container的外鍵,它在Container中創建了反向關係'''item_set'',因此SearchVector必須包含這些''''item_set'''條目。 – svfat
如果您要求某件事,而22K的某個人向您建議了一個答案,那麼一個好主意就是嘗試一下,而不是說「我認爲這不會起作用」。我發佈了在真實環境中逐步檢查它的答案。 – danihp
o_O哇,這真棒回答,我需要一些時間來了解它是如何工作的。感謝您的解決方案! – svfat