使用Django和Postgres进行全文搜索的实例代码


Posted in Python onFebruary 13, 2020

这些天,我需要全文搜索。这个区块中最酷的孩子们是Elastic Search和Sorl:他们快速,灵活,资源消耗沉重并且需要Java,这几乎是我想要的一个5美元的数字海洋飞车上运行的宠物项目所需的所有东西。

放弃这些选项后,我剩下了Xapian和postgres全文搜索的功能,而xapian似乎功能更丰富,我决定从postgres开始,因为它与django进行了本机集成,并且对这个特定项目的要求不高。

项目及其要求

您可能已经注意到,我正在运行工作板。 Voorjob基本上是从lever.co聚合工作,并让用户搜索它。目前,我在数据库中大约有25,000个工作,这个数字增长缓慢,每增加2或3个工作,就会关闭另一个工作。是的,如果我采用了弹性搜索路径,那将是一本教科书过度设计的情况。

实施

从9.4版开始,postgres添加了一些允许全文本搜索的功能。不久之后,Django在postgres特定功能中镜像了这些功能。

要开始使用此新功能,我基本上需要在模型中使用SearchVectorField,并需要使用矢量化的职位描述来更新此字段的方法:

from django.contrib.postgres.search import SearchVectorField, SearchVector
class Job(models.Model):
  title = models.CharField(max_length=200, blank=True)
  location = models.CharField(max_length=50, blank=True)
  body = models.TextField(null=True)
  body_vector = SearchVectorField(null=True)
 
  def make_search_vector():
    self.body_vector=SearchVector('body')
 
  def save(self, *args, **kwargs):
    self.make_search_vector()
    super(Model, self).save(*args, **kwargs)

这种方法适用于很少更新的工作,例如工作板,但是如果您的应用程序经常更新,则应避免使用此策略,并应定期执行一些任务来填充向量:

Job.objects.all().update(body_vector=SearchVector('body'))

甚至更好的是,您可以通过阅读本文档,使用postgres触发器直接进行操作。

查询工作

现在您已经准备好数据库,现在可以查询它了,让我们看一下voorjob搜索视图的教学版本:

from django.contrib.postgres.search import SearchQuery
 
class Index(ListView):
  model = Job
  paginate_by = 30
 
  def get_queryset(self):
    search = self.request.GET.get("search", None)
    queryset = Job.objects.all()
 
    if search:
      if '"' in search:
        query = SearchQuery(search.replace('"', ''), search_type='phrase')
      else:
        query = SearchQuery(search)
      queryset = queryset.filter(body_vector=query)
    else:
      queryset = queryset
 
    return queryset

我基本上在这里考虑两种查询:单词存在和“精确表达式”。是的,该逻辑中存在一些缺陷,请继续起诉我:D

还有很多可以改进的地方,django支持加权查询:

vector = SearchVector('title',weight ='A')+ SearchVector('body',weight ='B')
Job.objects.all()。update(body_vector = vector)

这最终将以更好的顺序返回结果,其中标题中的匹配比正文中的匹配更重。

查询系统也更加灵活,允许进行逻辑运算OR / AND和NOT。在不久的将来,我将改善对工作板的搜索,并更新此帖子以描述所做的更改。

性能

在开发过程中,我使用了具有16GB内存和不错的NVMe的I5。对本地计算机中的25k作业运行查询基本上是瞬时的。

当我将项目转移到生产环境时(每滴5美元),事情变得越来越慢了。

运行密西西比基准测试,我得到以下结果:

在/ django rest framework上搜索((1个密西西比州以扫描5K条目))

在/ full /上搜索“ django rest framework”(-3个密西西比州,扫描25K条目)

不是最好的性能,但现在可以使用。本文将进行更新以反映任何性能改进。

考虑到我的搜索需求不高-超过25k的条目,且字数过多的文章并不比本文大很多-使用postgres作为我的全文搜索的后端,对于此早期MVP来说效果很好。现在,我比每天给我20个用户提供最快的体验,对尝试事物和扩大董事会成员更感兴趣。

更新(2020年2月9日)

好消息! 我了解到可以将索引添加到SearchVectorField中:

from django.contrib.postgres.indexes import GinIndex
 
class Job(models.Model):
  class Meta:
    indexes = (GinIndex(fields=["body_vector"]),)
  title = models.CharField(max_length=200, blank=True)
  location = models.CharField(max_length=50, blank=True)
  body = models.TextField(null=True)
  body_vector = SearchVectorField(null=True)
  def make_search_vector():
    self.body_vector=SearchVector('body')
  def save(self, *args, **kwargs):
    self.make_search_vector()
    super(Model, self).save(*args, **kwargs)

现在,所有情况下的搜索时间均降至1个密西西比州。 由于我的数据很小,因此用于该索引的内存量可以忽略不计。

总结

以上所述是小编给大家介绍的使用Django和Postgres进行全文搜索的实例代码,希望对大家有所帮助!

Python 相关文章推荐
python处理PHP数组文本文件实例
Sep 18 Python
使用python实现knn算法
Dec 20 Python
详解python中asyncio模块
Mar 03 Python
python删除某个字符
Mar 19 Python
Django 中使用流响应处理视频的方法
Jul 20 Python
用python统计代码行的示例(包括空行和注释)
Jul 24 Python
python排序函数sort()与sorted()的区别
Sep 18 Python
Python socket实现多对多全双工通信的方法
Feb 13 Python
Python3+PyInstall+Sciter解决报错缺少dll、html等文件问题
Jul 15 Python
pandas实现DataFrame显示最大行列,不省略显示实例
Dec 26 Python
解决Python3.7.0 SSL低版本导致Pip无法使用问题
Sep 03 Python
Python OpenCV超详细讲解读取图像视频和网络摄像头
Apr 02 Python
解决python 找不到module的问题
Feb 12 #Python
pycharm 设置项目的根目录教程
Feb 12 #Python
Python3 Click模块的使用方法详解
Feb 12 #Python
pyecharts绘制中国2020肺炎疫情地图的实例代码
Feb 12 #Python
多个python文件调用logging模块报错误
Feb 12 #Python
Python对Tornado请求与响应的数据处理
Feb 12 #Python
在PyCharm中实现添加快捷模块
Feb 12 #Python
You might like
十天学会php之第二天
2006/10/09 PHP
php用header函数实现301跳转代码实例
2013/11/25 PHP
php使用curl检测网页是否被百度收录的示例分享
2014/01/31 PHP
php实现比较两个文件夹异同的方法
2015/06/18 PHP
总结PHP中数值计算的注意事项
2016/08/14 PHP
php魔法函数与魔法常量使用介绍
2017/07/23 PHP
JavaScript中的Location地址对象
2008/01/16 Javascript
jQuery 幻灯片插件(带缩略图功能)
2011/01/24 Javascript
Nodejs Express4.x开发框架随手笔记
2015/11/23 NodeJs
jQuery EasyUI学习教程之datagrid点击列表头排序
2016/07/09 Javascript
浅谈javascript控制HTML5的全屏操控,浏览器兼容的问题
2016/10/10 Javascript
JavaScript中Array对象用法实例总结
2016/11/29 Javascript
JS计算两个时间相差分钟数的方法示例
2018/01/10 Javascript
vue.js实现的幻灯片功能示例
2019/01/18 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
2019/08/23 Javascript
Node对CommonJS的模块规范
2019/11/06 Javascript
使用preload预加载页面资源时注意事项
2020/02/03 Javascript
python高手之路python处理excel文件(方法汇总)
2016/01/07 Python
解决python使用open打开文件中文乱码的问题
2017/12/29 Python
pytorch torch.expand和torch.repeat的区别详解
2019/11/05 Python
从numpy数组中取出满足条件的元素示例
2019/11/26 Python
django admin后管定制-显示字段的实例
2020/03/11 Python
浅谈keras中的Merge层(实现层的相加、相减、相乘实例)
2020/05/23 Python
详解Python多线程下的list
2020/07/03 Python
Html5 页面适配iPhoneX(就是那么简单)
2019/09/05 HTML / CSS
HTML5超文本标记语言的实现方法
2020/09/24 HTML / CSS
韩都衣舍天猫官方旗舰店:天猫女装销售总冠军
2017/10/10 全球购物
生物科学专业个人求职信范文
2013/12/05 职场文书
高中军训感言400字
2014/02/24 职场文书
校庆标语集锦
2014/06/25 职场文书
工作求职信
2014/07/04 职场文书
安全主题班会教案
2015/08/12 职场文书
小学主题班会教案
2015/08/17 职场文书
简单实现一个手持弹幕功能+文字抖动特效
2021/03/31 HTML / CSS
pytorch fine-tune 预训练的模型操作
2021/06/03 Python
解决SpringBoot文件上传临时目录找不到的问题
2021/07/01 Java/Android