![](/img/trans.png)
[英]Django/PostgreSQL Full Text Search - Different search results when using SearchVector versus SearchVectorField on AWS RDS PostgreSQL
[英]Django full text search using indexes with PostgreSQL
在解決了我在這個問題中提出的問題后,我正在嘗試使用索引來優化 FTS 的性能。 我在我的數據庫上發出了命令:
CREATE INDEX my_table_idx ON my_table USING gin(to_tsvector('italian', very_important_field), to_tsvector('italian', also_important_field), to_tsvector('italian', not_so_important_field), to_tsvector('italian', not_important_field), to_tsvector('italian', tags));
然后我編輯了我的模型的 Meta 類,如下所示:
class MyEntry(models.Model):
very_important_field = models.TextField(blank=True, null=True)
also_important_field = models.TextField(blank=True, null=True)
not_so_important_field = models.TextField(blank=True, null=True)
not_important_field = models.TextField(blank=True, null=True)
tags = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'my_table'
indexes = [
GinIndex(
fields=['very_important_field', 'also_important_field', 'not_so_important_field', 'not_important_field', 'tags'],
name='my_table_idx'
)
]
但似乎什么都沒有改變。 查找所用的時間與以前完全相同。
這是查找腳本:
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
# other unrelated stuff here
vector = SearchVector("very_important_field", weight="A") + \
SearchVector("tags", weight="A") + \
SearchVector("also_important_field", weight="B") + \
SearchVector("not_so_important_field", weight="C") + \
SearchVector("not_important_field", weight="D")
query = SearchQuery(search_string, config="italian")
rank = SearchRank(vector, query, weights=[0.4, 0.6, 0.8, 1.0]). # D, C, B, A
full_text_search_qs = MyEntry.objects.annotate(rank=rank).filter(rank__gte=0.4).order_by("-rank")
我究竟做錯了什么?
上面的查找包含在我使用裝飾器的函數中。 該函數實際上返回一個列表,如下所示:
@timeit
def search(search_string):
# the above code here
qs = list(full_text_search_qs)
return qs
這可能是問題,也許?
我不確定,但是根據postgresql文檔( https://www.postgresql.org/docs/9.5/static/textsearch-tables.html#TEXTSEARCH-TABLES-INDEX ):
因為在上面的索引中使用了to_tsvector的兩個參數的版本,所以只有使用具有相同配置名稱的to_tsvector的兩個參數的查詢引用才使用該索引。 也就是說,to_tsvector('english',body)@@'a&b'可以使用索引,而to_tsvector(body)@@'a&b'則不能使用索引。 這樣可以確保僅將索引用於創建索引條目的配置。
我不知道django使用什么配置,但是您可以嘗試刪除第一個參數
您需要將SearchVectorField
添加到您的MyEntry
中,從您的實際文本字段中更新它,然后在此字段上執行搜索。 但是,只有在記錄保存到數據庫后才能執行更新。
本質上:
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVector, SearchVectorField
class MyEntry(models.Model):
# The fields that contain the raw data.
very_important_field = models.TextField(blank=True, null=True)
also_important_field = models.TextField(blank=True, null=True)
not_so_important_field = models.TextField(blank=True, null=True)
not_important_field = models.TextField(blank=True, null=True)
tags = models.TextField(blank=True, null=True)
# The field we actually going to search.
# Must be null=True because we cannot set it immediately during create()
search_vector = SearchVectorField(editable=False, null=True)
class Meta:
# The search index pointing to our actual search field.
indexes = [GinIndex(fields=["search_vector"])]
然后您可以像往常一樣創建普通實例,例如:
# Does not set MyEntry.search_vector yet.
my_entry = MyEntry.objects.create(
very_important_field="something very important", # Fake Italien text ;-)
also_important_field="something different but equally important"
not_so_important_field="this one matters less"
not_important_field="we don't care are about that one at all"
tags="things, stuff, whatever"
現在該條目存在於數據庫中,您可以使用各種選項更新search_vector
字段。 例如weight
指定重要性和config
以使用默認語言配置之一。 您也可以完全省略您不想搜索的字段:
# Update search vector on existing database record.
my_entry.search_vector = (
SearchVector("very_important_field", weight="A", config="italien")
+ SearchVector("also_important_field", weight="A", config="italien")
+ SearchVector("not_so_important_field", weight="C", config="italien")
+ SearchVector("tags", weight="B", config="italien")
)
my_entry.save()
每次某些文本字段更改時手動更新search_vector
字段可能容易出錯,因此您可以考慮添加一個 SQL 觸發器來使用 Django 遷移為您執行此操作。 有關如何執行此操作的示例,請參閱有關使用 Django 和 PostgreSQL 進行全文搜索的博客文章。
要使用索引在MyEntry
中實際搜索,您需要按search_vector
字段進行過濾和排名。 SearchQuery
的config
應該與上面的SearchVector
之一匹配(使用相同的停用詞、詞干等)。
例如:
from django.contrib.postgres.search import SearchQuery, SearchRank
from django.core.exceptions import ValidationError
from django.db.models import F, QuerySet
search_query = SearchQuery("important", search_type="websearch", config="italien")
search_rank = SearchRank(F("search_vector"), search_query)
my_entries_found = (
MyEntry.objects.annotate(rank=search_rank)
.filter(search_vector=search_query) # Perform full text search on index.
.order_by("-rank") # Yield most relevant entries first.
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.