使用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合并文本文件示例
Feb 07 Python
Python两个内置函数 locals 和globals(学习笔记)
Aug 28 Python
python3+PyQt5+Qt Designer实现扩展对话框
Apr 20 Python
python 将json数据提取转化为txt的方法
Oct 26 Python
Python解析、提取url关键字的实例详解
Dec 17 Python
python实现AES加密解密
Mar 28 Python
python实现视频分帧效果
May 31 Python
docker django无法访问redis容器的解决方法
Aug 21 Python
关于python scrapy中添加cookie踩坑记录
Nov 17 Python
Jupyter Notebook添加代码自动补全功能的实现
Jan 07 Python
浅谈怎么给Python添加类型标注
Jun 08 Python
Python+Tkinter制作专属图形化界面
Apr 01 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
IIS+PHP+MySQL+Zend配置 (视频教程)
2006/12/13 PHP
PHP __autoload函数(自动载入类文件)的使用方法
2012/02/04 PHP
PHP中使用mktime获取时间戳的一个黑色幽默分析
2012/05/31 PHP
PHP简单实现文本计数器的方法
2016/04/28 PHP
PHP 自动加载的简单实现(推荐)
2016/08/12 PHP
javascript动态设置样式style实例分析
2015/05/13 Javascript
js实现Form栏显示全格式时间时钟效果代码
2015/08/19 Javascript
jquery拖拽效果完整实例(附demo源码下载)
2016/01/14 Javascript
Bootstrap学习笔记之css组件(3)
2016/06/07 Javascript
JavaScript学习笔记整理_关于表达式和语句
2016/09/19 Javascript
浅析script标签中的defer与async属性
2016/11/30 Javascript
AngularJS 文件上传控件 ng-file-upload详解
2017/01/13 Javascript
利用Jasmine对Angular进行单元测试的方法详解
2017/06/12 Javascript
ajax请求data遇到的问题分析
2018/01/18 Javascript
js实现圆形显示鼠标单击位置
2020/02/11 Javascript
Openlayers3实现车辆轨迹回放功能
2020/09/29 Javascript
[05:31]DOTA2英雄梦之声_第08期_莉娜
2014/06/23 DOTA
[01:02:30]Mineski vs Secret 2019国际邀请赛淘汰赛 败者组 BO3 第三场 8.22
2019/09/05 DOTA
Python单链表的简单实现方法
2014/09/23 Python
Python字符串格式化%s%d%f详解
2018/02/02 Python
Python 获取中文字拼音首个字母的方法
2018/11/28 Python
python 模拟贷款卡号生成规则过程解析
2019/08/30 Python
python数据预处理 :数据抽样解析
2020/02/24 Python
Python基于xlutils修改表格内容过程解析
2020/07/28 Python
Python学习笔记之装饰器
2020/08/06 Python
基于Python采集爬取微信公众号历史数据
2020/11/27 Python
python openssl模块安装及用法
2020/12/06 Python
CSS3 translate导致字体模糊的实例代码
2019/08/30 HTML / CSS
html5与css3小应用
2013/04/03 HTML / CSS
塔吉特百货公司官网:Target
2017/04/27 全球购物
初一生物教学反思
2014/01/18 职场文书
《在家里》教后反思
2014/03/01 职场文书
2016年世界艾滋病日宣传活动总结
2016/04/01 职场文书
python 实现德洛内三角剖分的操作
2021/04/22 Python
教你用Python写一个植物大战僵尸小游戏
2021/04/25 Python
利用 JavaScript 构建命令行应用
2021/11/17 Javascript