使用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的装饰器解决Bottle框架中用户验证问题
Apr 24 Python
python使用str & repr转换字符串
Oct 13 Python
python3.6+django2.0开发一套学员管理系统
Mar 03 Python
解决pycharm无法调用pip安装的包问题
May 18 Python
win7+Python3.5下scrapy的安装方法
Jul 31 Python
Python 从列表中取值和取索引的方法
Dec 25 Python
详解js文件通过python访问数据库方法
Mar 03 Python
Dlib+OpenCV深度学习人脸识别的方法示例
May 14 Python
Python如何执行精确的浮点数运算
Jul 31 Python
django数据模型中null和blank的区别说明
Sep 02 Python
scrapy中如何设置应用cookies的方法(3种)
Sep 22 Python
PyCharm 安装与使用配置教程(windows,mac通用)
May 12 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
Codeigniter控制器controller继承问题实例分析
2016/01/19 PHP
Centos6.5和Centos7 php环境搭建方法
2016/05/27 PHP
PHP crc32()函数讲解
2019/02/14 PHP
laravel5.5添加echarts实现画图功能的方法
2019/10/09 PHP
利用jQuery操作对象数组的实现代码
2011/04/27 Javascript
addEventListener()第三个参数useCapture (Boolean)详细解析
2013/11/07 Javascript
网页防止tab键的使用快速解决方法
2013/11/07 Javascript
jquery基础教程之数组使用详解
2014/03/10 Javascript
JavaScript中的console.assert()函数介绍
2014/12/29 Javascript
Javascript中的几种URL编码方法比较
2015/01/23 Javascript
jQuery实现分隔条左右拖动功能
2015/11/21 Javascript
JAVASCRIPT代码编写俄罗斯方块网页版
2015/11/26 Javascript
JavaScript中的this引用(推荐)
2016/08/05 Javascript
十大热门的JavaScript框架和库
2017/03/21 Javascript
解决vue项目打包后提示图片文件路径错误的问题
2018/07/04 Javascript
vue浏览器返回监听的具体步骤
2021/02/03 Vue.js
python使用分治法实现求解最大值的方法
2015/05/12 Python
Python捕捉和模拟鼠标事件的方法
2015/06/03 Python
Python编程中的文件读写及相关的文件对象方法讲解
2016/01/19 Python
Python实现http接口自动化测试的示例代码
2020/10/09 Python
html5 分层屏幕适配的方法
2018/03/16 HTML / CSS
Html5游戏开发之乒乓Ping Pong游戏示例(一)
2013/01/21 HTML / CSS
canvas 橡皮筋式线条绘图应用方法
2019/02/13 HTML / CSS
Hotels.com日本:国外和海外住宿,酒店预订
2019/12/13 全球购物
如何通过jdbc调用存储过程
2012/04/19 面试题
新闻专业个人自我评价
2013/09/21 职场文书
2014年高三班主任工作总结
2014/12/05 职场文书
预备党员群众意见
2015/06/01 职场文书
大学军训通讯稿
2015/07/18 职场文书
公司员工离职感言
2015/08/03 职场文书
谢师宴学生答谢词
2015/09/30 职场文书
导游词之太原天龙山
2020/01/02 职场文书
python数据分析之用sklearn预测糖尿病
2021/04/22 Python
详解PHP Swoole与TCP三次握手
2021/05/27 PHP
python数字转对应中文的方法总结
2021/08/02 Python
攻击最高的10只幽灵系神奇宝贝,坚盾剑怪排第一,第五最为可怕
2022/03/18 日漫