使用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网络编程步骤详解(socket套接字使用)
Dec 06 Python
python使用自定义user-agent抓取网页的方法
Apr 15 Python
Python的Bottle框架中返回静态文件和JSON对象的方法
Apr 30 Python
收藏整理的一些Python常用方法和技巧
May 18 Python
好用的Python编辑器WingIDE的使用经验总结
Aug 31 Python
使用python实现tcp自动重连
Jul 02 Python
利用numpy和pandas处理csv文件中的时间方法
Apr 19 Python
Python GUI Tkinter简单实现个性签名设计
Jun 19 Python
Python函数装饰器常见使用方法实例详解
Mar 30 Python
Python多线程threading join和守护线程setDeamon原理详解
Mar 18 Python
浅析python 通⽤爬⾍和聚焦爬⾍
Sep 28 Python
浅析Python的命名空间与作用域
Nov 25 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
手把手教你使用DedeCms的采集的图文教程
2007/03/11 PHP
PHP不用第三变量交换2个变量的值的解决方法
2013/06/02 PHP
PHP与Java进行通信的实现方法
2013/10/21 PHP
淘宝ip地址查询类分享(利用淘宝ip库)
2014/01/07 PHP
php统计时间和内存使用情况示例分享
2014/03/13 PHP
php使用Jpgraph创建折线图效果示例
2017/02/15 PHP
PHP简单获取上月、本月、近15天、近30天的方法示例
2017/07/03 PHP
php empty 函数判断结果为空但实际值却为非空的原因解析
2018/05/28 PHP
PHP实现的敏感词过滤方法示例
2019/03/06 PHP
js 模拟气泡屏保效果代码
2010/07/10 Javascript
JQuery的Ajax跨域请求原理概述及实例
2013/04/26 Javascript
JQuery调用WebServices的方法和4个实例
2014/05/06 Javascript
FF(火狐)浏览器无法执行window.close()解决方案
2014/11/13 Javascript
Web开发必知Javascript技巧大全
2016/02/23 Javascript
JS中input表单隐藏域及其使用方法
2017/02/13 Javascript
JavaScript数据结构之二叉树的遍历算法示例
2017/04/13 Javascript
微信小程序实现YDUI的ScrollNav组件
2018/02/02 Javascript
原生JS实现的双色球功能示例
2018/02/02 Javascript
js中实例与对象的区别讲解
2019/01/21 Javascript
浅谈JavaScript面向对象--继承
2019/03/20 Javascript
深入理解 JS 垃圾回收
2019/06/03 Javascript
浅谈对于“不用setInterval,用setTimeout”的理解
2019/08/28 Javascript
在vue中使用回调函数,this调用无效的解决
2020/08/11 Javascript
pandas获取groupby分组里最大值所在的行方法
2018/04/20 Python
Python使用pickle模块报错EOFError Ran out of input的解决方法
2018/08/16 Python
python使用KNN算法识别手写数字
2019/04/25 Python
django框架forms组件用法实例详解
2019/12/10 Python
python如何利用Mitmproxy抓包
2020/10/10 Python
CSS3 边框效果
2019/11/04 HTML / CSS
html5中canvas图表实现柱状图的示例
2017/11/13 HTML / CSS
美国摄影爱好者购物网站:Focus Camera
2016/10/21 全球购物
蛋糕店创业计划书
2014/05/06 职场文书
超市开业庆典活动策划方案
2014/09/15 职场文书
2014年惩防体系建设工作总结
2014/12/01 职场文书
我的1919观后感
2015/06/03 职场文书
怎样写工作总结啊!
2019/06/18 职场文书