全文檢索¶
django.contrib.postgres.search
模組中的資料庫函式簡化了 PostgreSQL 的全文檢索引擎的使用。
在本文件中,我們將使用製作查詢中定義的模型。
另請參閱
有關搜尋的高階概述,請參閱主題文件。
search
查詢條件¶
使用全文檢索的常見方法是針對資料庫中的單一欄位搜尋單一詞彙。例如
>>> Entry.objects.filter(body_text__search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
這會從 body_text
欄位在資料庫中建立 to_tsvector
,並從搜尋詞彙 'Cheese'
建立 plainto_tsquery
,兩者都使用預設的資料庫搜尋設定。結果是透過比對查詢和向量來取得。
若要使用 search
查詢條件,'django.contrib.postgres'
必須在您的 INSTALLED_APPS
中。
SearchVector
¶
針對單一欄位進行搜尋很棒,但相當有限。Entry
我們正在搜尋的執行個體屬於 Blog
,其中具有 tagline
欄位。若要針對兩個欄位進行查詢,請使用 SearchVector
>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
... search=SearchVector("body_text", "blog__tagline"),
... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
SearchVector
的引數可以是任何 Expression
或欄位的名稱。多個引數將會以空格串連在一起,讓搜尋文件包含所有引數。
SearchVector
物件可以組合在一起,讓您可以重複使用它們。例如
>>> Entry.objects.annotate(
... search=SearchVector("body_text") + SearchVector("blog__tagline"),
... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
SearchQuery
¶
SearchQuery
會將使用者提供的詞彙翻譯成資料庫與搜尋向量比較的搜尋查詢物件。根據預設,使用者提供的所有單字都會經過詞幹演算法處理,然後它會尋找所有結果詞彙的相符項目。
如果 search_type
為 'plain'
(預設值),詞彙會被視為個別關鍵字。如果 search_type
為 'phrase'
,詞彙會被視為單一詞組。如果 search_type
為 'raw'
,則您可以提供具有詞彙和運算子的格式化搜尋查詢。如果 search_type
為 'websearch'
,則您可以提供格式化的搜尋查詢,與網頁搜尋引擎使用的查詢類似。'websearch'
需要 PostgreSQL ≥ 11。請閱讀 PostgreSQL 的全文檢索文件,以了解差異和語法。範例
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery("red tomato") # two keywords
>>> SearchQuery("tomato red") # same results as above
>>> SearchQuery("red tomato", search_type="phrase") # a phrase
>>> SearchQuery("tomato red", search_type="phrase") # a different phrase
>>> SearchQuery("'tomato' & ('red' | 'green')", search_type="raw") # boolean operators
>>> SearchQuery(
... "'tomato' ('red' OR 'green')", search_type="websearch"
... ) # websearch operators
SearchQuery
詞彙可以邏輯方式組合,以提供更大的彈性
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery("meat") & SearchQuery("cheese") # AND
>>> SearchQuery("meat") | SearchQuery("cheese") # OR
>>> ~SearchQuery("meat") # NOT
請參閱變更搜尋設定以了解 config
參數的說明。
SearchRank
¶
到目前為止,我們傳回了向量和查詢之間任何可能相符的結果。您可能希望依某種相關性排序結果。PostgreSQL 提供排名函數,此函數會考量查詢詞彙在文件中出現的頻率、詞彙在文件中彼此之間的距離,以及詞彙出現的文件部分的重要性。比對程度越高,排名的值就越高。若要依相關性排序
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector("body_text")
>>> query = SearchQuery("cheese")
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by("-rank")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
請參閱加權查詢以了解 weights
參數的說明。
將 cover_density
參數設定為 True
,以啟用涵蓋密度排名,這表示會考量比對查詢詞彙的接近程度。
提供整數給 normalization
參數,以控制排名正規化。此整數是位元遮罩,因此您可以組合多個行為
>>> from django.db.models import Value
>>> Entry.objects.annotate(
... rank=SearchRank(
... vector,
... query,
... normalization=Value(2).bitor(Value(4)),
... )
... )
PostgreSQL 文件中有關不同排名正規化選項的詳細資訊。
SearchHeadline
¶
- class SearchHeadline(expression, query, config=None, start_sel=None, stop_sel=None, max_words=None, min_words=None, short_word=None, highlight_all=None, max_fragments=None, fragment_delimiter=None)[原始碼]¶
接受單一文字欄位或運算式、查詢、設定和一組選項。傳回醒目提示的搜尋結果。
將 start_sel
和 stop_sel
參數設定為用於包覆文件中醒目提示的查詢詞彙的字串值。PostgreSQL 的預設值為 <b>
和 </b>
。
提供整數值給 max_words
和 min_words
參數,以判斷最長和最短標題。PostgreSQL 的預設值為 35 和 15。
提供整數值給 short_word
參數,以捨棄每個標題中長度小於或等於此長度的單字。PostgreSQL 的預設值為 3。
將 highlight_all
參數設定為 True
,即可使用整個文件來代替片段,並忽略 max_words
、min_words
和 short_word
參數。在 PostgreSQL 中,此設定預設為停用。
為 max_fragments
提供一個非零的整數值,以設定要顯示的最大片段數。在 PostgreSQL 中,此設定預設為停用。
設定 fragment_delimiter
字串參數以設定片段之間的分隔符號。PostgreSQL 的預設值為 " ... "
。
PostgreSQL 文件中有關於高亮顯示搜尋結果的更多詳細資訊。
使用範例
>>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
>>> query = SearchQuery("red tomato")
>>> entry = Entry.objects.annotate(
... headline=SearchHeadline(
... "body_text",
... query,
... start_sel="<span>",
... stop_sel="</span>",
... ),
... ).get()
>>> print(entry.headline)
Sandwich with <span>tomato</span> and <span>red</span> cheese.
請參閱變更搜尋設定以了解 config
參數的說明。
變更搜尋設定¶
您可以將 config
屬性指定給 SearchVector
和 SearchQuery
,以使用不同的搜尋設定。這允許使用資料庫定義的不同語言剖析器和字典。
>>> from django.contrib.postgres.search import SearchQuery, SearchVector
>>> Entry.objects.annotate(
... search=SearchVector("body_text", config="french"),
... ).filter(search=SearchQuery("œuf", config="french"))
[<Entry: Pain perdu>]
config
的值也可以儲存在另一個欄位中。
>>> from django.db.models import F
>>> Entry.objects.annotate(
... search=SearchVector("body_text", config=F("blog__language")),
... ).filter(search=SearchQuery("œuf", config=F("blog__language")))
[<Entry: Pain perdu>]
加權查詢¶
每個欄位在查詢中可能具有不同的相關性,因此您可以在組合它們之前設定各種向量的權重。
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector("body_text", weight="A") + SearchVector(
... "blog__tagline", weight="B"
... )
>>> query = SearchQuery("cheese")
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by(
... "rank"
... )
權重應該是以下字母之一:D、C、B、A。預設情況下,這些權重分別代表數字 0.1
、0.2
、0.4
和 1.0
。如果您希望以不同的方式加權,請將四個浮點數的列表以相同的順序傳遞給 SearchRank
作為 weights
。
>>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
>>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by("-rank")
效能¶
使用這些函數不需要特殊的資料庫設定,但是,如果您搜尋的記錄超過幾百筆,您很可能會遇到效能問題。全文搜尋是一個比比較整數大小更密集運算的過程,舉例來說。
如果您查詢的所有欄位都包含在一個特定的模型中,您可以建立一個與您想要使用的搜尋向量相匹配的功能性 GIN
或 GiST
索引。例如
GinIndex(
SearchVector("body_text", "headline", config="english"),
name="search_vector_idx",
)
PostgreSQL 文件中有關於建立全文搜尋索引的詳細資訊。
SearchVectorField
¶
如果這種方法變得太慢,您可以將 SearchVectorField
新增到您的模型中。您需要使用觸發器來保持它被填充,例如,如PostgreSQL 文件中所述。然後您可以像查詢帶有註解的 SearchVector
一樣查詢該欄位。
>>> Entry.objects.update(search_vector=SearchVector("body_text"))
>>> Entry.objects.filter(search_vector="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
三元組相似度¶
另一種搜尋方法是三元組相似度。三元組是三個連續字元的組合。除了 trigram_similar
、trigram_word_similar
和 trigram_strict_word_similar
查找外,您可以使用其他幾個表達式。
要使用它們,您需要在 PostgreSQL 上啟用 pg_trgm 擴充功能。您可以使用 TrigramExtension
遷移操作來安裝它。
TrigramSimilarity
¶
接受欄位名稱或表達式,以及字串或表達式。傳回兩個引數之間的三元組相似度。
使用範例
>>> from django.contrib.postgres.search import TrigramSimilarity
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Katie Stephens"
>>> Author.objects.annotate(
... similarity=TrigramSimilarity("name", test),
... ).filter(
... similarity__gt=0.3
... ).order_by("-similarity")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
TrigramWordSimilarity
¶
接受字串或表達式,以及欄位名稱或表達式。傳回兩個引數之間的三元組詞相似度。
使用範例
>>> from django.contrib.postgres.search import TrigramWordSimilarity
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Kat"
>>> Author.objects.annotate(
... similarity=TrigramWordSimilarity(test, "name"),
... ).filter(
... similarity__gt=0.3
... ).order_by("-similarity")
[<Author: Katy Stevens>]
TrigramStrictWordSimilarity
¶
接受字串或表達式,以及欄位名稱或表達式。傳回兩個引數之間的三元組嚴格詞相似度。與 TrigramWordSimilarity()
相似,只是它強制範圍邊界與詞邊界匹配。
TrigramDistance
¶
接受欄位名稱或表達式,以及字串或表達式。傳回兩個引數之間的三元組距離。
使用範例
>>> from django.contrib.postgres.search import TrigramDistance
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Katie Stephens"
>>> Author.objects.annotate(
... distance=TrigramDistance("name", test),
... ).filter(
... distance__lte=0.7
... ).order_by("distance")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
TrigramWordDistance
¶
接受字串或表達式,以及欄位名稱或表達式。傳回兩個引數之間的三元組詞距離。
使用範例
>>> from django.contrib.postgres.search import TrigramWordDistance
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Kat"
>>> Author.objects.annotate(
... distance=TrigramWordDistance(test, "name"),
... ).filter(
... distance__lte=0.7
... ).order_by("distance")
[<Author: Katy Stevens>]
TrigramStrictWordDistance
¶
接受字串或表達式,以及欄位名稱或表達式。傳回兩個引數之間的三元組嚴格詞距離。