使用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实现探测socket和web服务示例
Mar 28 Python
Python的高级Git库 Gittle
Sep 22 Python
python列表操作实例
Jan 14 Python
在Python中操作字典之setdefault()方法的使用
May 21 Python
利用Python脚本生成sitemap.xml的实现方法
Jan 31 Python
python放大图片和画方格实现算法
Mar 30 Python
Python图像处理之识别图像中的文字(实例讲解)
May 10 Python
python 用lambda函数替换for循环的方法
Jun 09 Python
基于Python函数和变量名解析
Jul 19 Python
postman传递当前时间戳实例详解
Sep 14 Python
使用Python实现Wake On Lan远程开机功能
Jan 22 Python
Python实现壁纸下载与轮换
Oct 19 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
一个简易需要注册的留言版程序
2006/10/09 PHP
PHP与MySQL开发中页面乱码的产生与解决
2008/03/27 PHP
Wordpress php 分页代码
2009/10/21 PHP
php数组去重复数据示例
2014/02/25 PHP
php传值方式和ajax的验证功能
2017/03/27 PHP
PHP等比例压缩图片的实例代码
2018/07/26 PHP
JavaScript的类型简单说明
2010/09/03 Javascript
jQuery弹出层始终垂直居中相对于屏幕或当前窗口
2013/04/01 Javascript
把文本中的URL地址转换为可点击链接的JavaScript、PHP自定义函数
2014/07/29 Javascript
jquery表单验证插件(jquery.validate.js)的3种使用方式
2015/03/28 Javascript
jquery插件qrcode在线生成二维码
2015/04/26 Javascript
PHP+jQuery+Ajax+Mysql如何实现发表心情功能
2015/08/06 Javascript
全面解析Bootstrap手风琴效果
2020/04/17 Javascript
解析Javascript单例模式概念与实例
2016/12/05 Javascript
H5手机端多文件上传预览插件
2017/04/21 Javascript
一个可复用的vue分页组件
2017/05/15 Javascript
基于AngularJS实现的工资计算器实例
2017/06/16 Javascript
微信小程序 JS动态修改样式的实现方法
2018/12/16 Javascript
Vue包大小优化的实现(从1.72M到94K)
2021/02/18 Vue.js
vue实现可移动的悬浮按钮
2021/03/04 Vue.js
详解python中的线程与线程池
2019/05/10 Python
使用APScheduler3.0.1 实现定时任务的方法
2019/07/22 Python
Python MongoDB 插入数据时已存在则不执行,不存在则插入的解决方法
2019/09/24 Python
Django Form and ModelForm的区别与使用
2019/12/06 Python
Python super()方法原理详解
2020/03/31 Python
Pycharm连接远程服务器过程图解
2020/04/30 Python
Win 10下Anaconda虚拟环境的教程
2020/05/18 Python
pygame用blit()实现动画效果的示例代码
2020/05/28 Python
Python 忽略文件名编码的方法
2020/08/01 Python
将世界上最美丽的摄影作品转化为艺术作品:Photos.com
2017/11/28 全球购物
英国豪华真皮和布艺沙发销售网站:Darlings of Chelsea
2018/01/05 全球购物
英国手工制作的现代与经典的沙发和床:Love Your Home
2020/09/26 全球购物
中学教师暑期培训方案
2014/08/27 职场文书
Mysql分库分表之后主键处理的几种方法
2022/02/15 MySQL
vue中使用mockjs配置和使用方式
2022/04/06 Vue.js
解决springboot druid数据库连接失败后一直重连的方法
2022/04/19 Java/Android