django.contrib.postgres的新TrigramSimilarity特性对于我遇到的一个问题来说非常好。我用它作为一个搜索栏来查找很难拼写的拉丁名字。问题是有超过200万个名字,搜索的时间比我想要的要长。
我想在postgres documentation中描述的三元组上创建一个索引。
但我不确定如何以Django API使用它的方式来做到这一点。对于postgres文本搜索,有关于如何创建索引的描述,但没有关于三元组相似性的描述。
这就是我现在所拥有的:
class NCBI_names(models.Model):
tax_id = models.ForeignKey(NCBI_nodes, on_delete=models.CASCADE, default = 0)
name_txt = models.CharField(max_length=255, default = '')
name_class = models.CharField(max_length=32, db_index=True, default = '')
class Meta:
indexes = [GinIndex(fields=['name_txt'])]
在视图的get_queryset
方法中:
class TaxonSearchListView(ListView):
#form_class=TaxonSearchForm
template_name='collectie/taxon_list.html'
paginate_by=20
model=NCBI_names
context_object_name = 'taxon_list'
def dispatch(self, request, *args, **kwargs):
query = request.GET.get('q')
if query:
try:
tax_id = self.model.objects.get(name_txt__iexact=query).tax_id.tax_id
return redirect('collectie:taxon_detail', tax_id)
except (self.model.DoesNotExist, self.model.MultipleObjectsReturned) as e:
return super(TaxonSearchListView, self).dispatch(request, *args, **kwargs)
else:
return super(TaxonSearchListView, self).dispatch(request, *args, **kwargs)
def get_queryset(self):
result = super(TaxonSearchListView, self).get_queryset()
#
query = self.request.GET.get('q')
if query:
result = result.exclude(name_txt__icontains = 'sp.')
result = result.annotate(similarity=TrigramSimilarity('name_txt', query)).filter(similarity__gt=0.3).order_by('-similarity')
return result
6条答案
按热度按时间34gzjxbg1#
我发现了一个使用最新版本Django ORM的12/2020 article:
如果像最初的海报一样,你想创建一个与icontains一起工作的索引,你必须索引列的UPPER(),这需要OpClass的特殊处理:
受old article的启发,我使用了current one,它给出了
GistIndex
的以下解决方案:更新:从Django-1.11开始,事情似乎更简单了,因为this answer和django文档建议:
从Django-2.2开始,
class Index(fields=(), name=None, db_tablespace=None, opclasses=())
中将提供一个属性opclasses
用于此目的。然后你可以在你的模型类中像这样使用它:
z6psavjg2#
我也遇到了类似的问题,试图使用
pg_tgrm
扩展来支持高效的contains
和icontains
Django字段查找。可能有一种更优雅的方法,但定义一个新的索引类型对我来说是有效的:
方法
get_sql_create_template_values
是从Index.get_sql_create_template_values()
复制而来的,只有一处修改:添加+ ' gin_trgm_ops'
。对于您的用例,您可以使用这个
TrigramIndex
而不是GinIndex
在name_txt
上定义索引。然后运行makemigrations
,这将产生一个迁移,生成所需的CREATE INDEX
SQL。更新:
我看到你也在使用
icontains
进行查询:Postgresql后端会把它变成这样:
然后由于
UPPER()
,将不使用三元组索引。我也遇到了同样的问题,最后我将数据库后端子类化来解决这个问题:
isr3a4wc3#
这已经有了答案,但在Django 2.2中,你可以更容易地做到这一点:
您也可以使用
GinIndex
。sr4lhrrt4#
让Django 2.2使用
icontains
和类似搜索的索引:子类GinIndex创建一个不区分大小写的索引(所有字段值都大写):
像这样将索引添加到模型中,包括使用
opclasses
时需要的kwargname
:生成迁移并编辑生成的文件:
ef1yzkbh5#
如果有人想在多个列上用空格连接索引,你可以使用我的内置索引。
创建类似
gin (("column1" || ' ' || "column2" || ' ' || ...) gin_trgm_ops)
的索引bnlyeluc6#
确保已将
django.contrib.postgres
添加到INSTALLED_APPS
来源https://code.djangoproject.com/ticket/32770