Dies ist die Art und Weise:
- Seien Sie sicher, dass Sie Arbeiten mit Django -gte 1.10
- Seien Sie sicher, Sie haben
'django.contrib.postgres',
auf Ihrem INSTALLED_APPS
- Erstellen Sie Ihre beiden Modelle wie in Ihrer Frage.
- Nur makemigrations, wandern und bevölkern Modelle mit einigen Daten:
Bestücken Modelle mit Daten:
from fts.models import Item, Container
c=Container.objects.create(text = "hello")
Item.objects.create(text ="Some word", container = c)
- An dieser Stelle Sie bereit sind, die machen query:
Abfragen und Kontrolle Ergebnisse:
from django.contrib.postgres.search import SearchVector
>>> (Container
... .objects
... .annotate(search=SearchVector('text', 'item__text'),)
... .filter(search='Some word')
... .distinct()
... )
Ergebnisse wie erwartet:
<QuerySet [<Container: Container object>]>
- Nur um sicherzugehen Ihre Abfrage vollständige Suche Postgres Fähigkeiten mit arbeitet, können Sie die zugrunde liegende SQL ausdrucken:
Bitte um darunter liegende SQL:
>>> print (Container
.objects
.annotate(search=SearchVector('text', 'item__text'),)
.filter(search='Some word')
).query
und das Ergebnis ist:
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
In Aktion:
Performance:
Ich weiß nicht, ob Postgres der Lage ist, auf volle Suchfunktionen Vorteil aus dem Index zu nehmen, wenn Sie Mischfelder aus mehreren Tabellen. Aber es ist einfach, es zu überprüfen. Nach dem Erstellen Volltextindizes und ANALYZE Ihre Tabellen können Sie über SQL-Plan fragen:
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)
denke ich, das sollte funktionieren, wenn Sie '' 'haben item = models.ForeignKey (Item)' '' in Containern. Aber in meinem Snippet habe ich einen Fremdschlüssel für Container im Item-Modell, der eine umgekehrte Relation '' 'item_set''' in Container erzeugt, also muss SearchVector diese' '' item_set''' Einträge enthalten. – svfat
Wenn Sie nach etwas fragen und jemand mit 22K Ihnen eine Antwort vorschlägt, ist es eine gute Idee, es stattdessen zu versuchen, um zu sagen: "Ich denke, das wird nicht funktionieren".Ich postete die Antwort und überprüfte sie Schritt für Schritt in der realen Umgebung. – danihp
o_O Whoa, das ist eine tolle Antwort, ich brauche etwas Zeit um zu verstehen, wie es funktioniert. Danke für die Lösung! – svfat