使用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 相关文章推荐
在Django框架中运行Python应用全攻略
Jul 17 Python
简要讲解Python编程中线程的创建与锁的使用
Feb 28 Python
Python中内置的日志模块logging用法详解
Jul 12 Python
老生常谈Python基础之字符编码
Jun 14 Python
简述Python2与Python3的不同点
Jan 21 Python
python实现壁纸批量下载代码实例
Jan 25 Python
python 使用pygame工具包实现贪吃蛇游戏(多彩版)
Oct 30 Python
python 实现一个反向单位矩阵示例
Nov 29 Python
Python无头爬虫下载文件的实现
Apr 02 Python
关于python中导入文件到list的问题
Oct 31 Python
Pytorch中的数据集划分&正则化方法
May 27 Python
python实现Nao机器人的单目测距
Sep 04 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个人网站架设连环讲(三)
2006/10/09 PHP
php下intval()和(int)转换使用与区别
2008/07/18 PHP
php5 图片验证码实现代码
2009/12/11 PHP
深入file_get_contents与curl函数的详解
2013/06/25 PHP
destoon网站转移服务器后搜索汉字出现乱码的解决方法
2014/06/21 PHP
PHP文件操作方法汇总
2015/07/01 PHP
php无序树实现方法
2015/07/28 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
PHP实现双链表删除与插入节点的方法示例
2017/11/11 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
2012/07/31 Javascript
JavaScript获取多个数组的交集简单实例
2013/11/11 Javascript
js控制淡入淡出示例代码
2013/11/12 Javascript
node.js中的fs.existsSync方法使用说明
2014/12/17 Javascript
jQuery实现下拉菜单(内容为时间)的实时更新及图表的随动更新的方法
2016/07/07 Javascript
基于jQuery选择器之表单对象属性筛选选择器的实例
2017/09/19 jQuery
vue2组件之select2调用的示例代码
2017/10/12 Javascript
JS检测浏览器开发者工具是否打开的方法详解
2020/10/02 Javascript
Jupyter notebook在mac:linux上的配置和远程访问的方法
2019/01/14 Python
Python几种常见算法汇总
2020/06/02 Python
Pandas中两个dataframe的交集和差集的示例代码
2020/12/13 Python
python编写扎金花小程序的实例代码
2021/02/23 Python
意大利奢侈品综合电商网站:MODES
2019/12/14 全球购物
英国钻石公司:British Diamond Company
2020/02/16 全球购物
校园活动策划书范文
2014/01/10 职场文书
会议接待欢迎词
2014/01/12 职场文书
五年级科学教学反思
2014/02/05 职场文书
小学学雷锋活动总结
2014/04/25 职场文书
大学优秀班主任事迹材料
2014/05/02 职场文书
最常使用的求职信
2014/05/25 职场文书
我的梦想演讲稿1000字
2014/08/21 职场文书
学术研讨会欢迎词
2015/01/26 职场文书
地震捐款简报
2015/07/21 职场文书
对Golang中的FORM相关字段理解
2021/05/02 Golang
Spring中的@Transactional的工作原理
2022/06/05 Java/Android