使用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中os和shutil模块实用方法集锦
May 13 Python
Python中urllib+urllib2+cookielib模块编写爬虫实战
Jan 20 Python
查看TensorFlow checkpoint文件中的变量名和对应值方法
Jun 14 Python
python版本单链表实现代码
Sep 28 Python
Python之使用adb shell命令启动应用的方法详解
Jan 07 Python
使用python脚本自动创建pip.ini配置文件代码实例
Sep 20 Python
tensorflow 只恢复部分模型参数的实例
Jan 06 Python
Python3搭建http服务器的实现代码
Feb 11 Python
python手机号前7位归属地爬虫代码实例
Mar 31 Python
如何在windows下安装配置python工具Ulipad
Oct 27 Python
在 Golang 中实现 Cache::remember 方法详解
Mar 30 Python
总结Pyinstaller打包的高级用法
Jun 28 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
php5 pdo新改动加载注意事项
2008/09/11 PHP
PHP在字符串中查找指定字符串并删除的代码
2008/10/02 PHP
php操作xml
2013/10/27 PHP
ThinkPHP中的三大自动简介
2014/08/22 PHP
Windows下Apache + PHP SESSION丢失的解决过程全纪录
2015/04/07 PHP
JS获取月的最后一天与JS得到一个月份最大天数的实例代码
2013/12/16 Javascript
js简单的点击返回顶部效果实现方法
2015/04/10 Javascript
jQuery实现摸拟alert提示框
2016/05/22 Javascript
浅析如何利用JavaScript进行语音识别
2016/10/27 Javascript
jQuery居中元素scrollleft计算方法示例
2017/01/16 Javascript
通过js控制时间,一秒一秒自己动的实例
2017/10/25 Javascript
解决Vue.js应用回退或刷新界面时提示用户保存修改问题
2019/11/24 Javascript
js 计算月/周的第一天和最后一天代码
2020/02/01 Javascript
js实现经典贪吃蛇小游戏
2020/03/19 Javascript
python2.7删除文件夹和删除文件代码实例
2013/12/18 Python
linux系统使用python监控apache服务器进程脚本分享
2014/01/15 Python
用Python编写分析Python程序性能的工具的教程
2015/04/01 Python
由Python运算π的值深入Python中科学计算的实现
2015/04/17 Python
Python中的time模块与datetime模块用法总结
2016/06/30 Python
python实现八大排序算法(2)
2017/09/14 Python
Python基于identicon库创建类似Github上用的头像功能
2017/09/25 Python
Python快速排序算法实例分析
2017/11/29 Python
python 统计一个列表当中的每一个元素出现了多少次的方法
2018/11/14 Python
python中对数据进行各种排序的方法
2019/07/02 Python
Pytorch Tensor基本数学运算详解
2019/12/30 Python
Python实现投影法分割图像示例(二)
2020/01/17 Python
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
美国蔬菜和植物种子公司:Burpee
2017/02/01 全球购物
德国富尔达运动鞋店:43einhalb
2020/12/25 全球购物
大学辅导员事迹材料
2014/02/05 职场文书
劳动纠纷调解协议书格式
2014/11/30 职场文书
承德避暑山庄导游词
2015/02/03 职场文书
社区服务活动报告
2015/02/05 职场文书
合作协议书格式范本
2016/03/21 职场文书
ORACLE数据库对long类型字段进行模糊匹配的解决思路
2021/04/07 Oracle
win10频率超出范围怎么办?win10老显示超出工作频率范围的解决方法
2022/07/07 数码科技