使用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写的windows服务不能启动的问题
Apr 15 Python
python连接oracle数据库实例
Oct 17 Python
python 常用的基础函数
Jul 10 Python
Sanic框架基于类的视图用法示例
Jul 18 Python
python地震数据可视化详解
Jun 18 Python
pandas read_excel()和to_excel()函数解析
Sep 19 Python
python根据时间获取周数代码实例
Sep 30 Python
使用Python函数进行模块化的实现
Nov 15 Python
python3 实现口罩抽签的功能
Mar 11 Python
python中可以声明变量类型吗
Jun 18 Python
python3:excel操作之读取数据并返回字典 + 写入的案例
Sep 01 Python
Python用dilb提取照片上人脸的示例
Oct 26 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
php mssql 日期出现中文字符的解决方法
2009/03/10 PHP
PHP 观察者模式的实现代码
2013/05/10 PHP
JoshChen_web格式编码UTF8-无BOM的小细节分析
2013/08/16 PHP
一致性哈希算法以及其PHP实现详细解析
2013/08/24 PHP
php实现根据词频生成tag云的方法
2015/04/17 PHP
php5.2的curl-bug 服务器被php进程卡死问题排查
2016/09/19 PHP
thinkPHP中验证码的简单实现方法
2016/12/05 PHP
PHP APP微信提现接口代码
2018/09/30 PHP
使用TextRange获取输入框中光标的位
2006/10/14 Javascript
jQuery 使用手册(五)
2009/09/23 Javascript
让mayfish支持mysqli数据库驱动的实现方法
2010/05/22 Javascript
浅析JS刷新框架中的其他页面 && JS刷新窗口方法汇总
2013/07/08 Javascript
各种页面定时跳转(倒计时跳转)代码总结
2013/10/24 Javascript
js/jquery解析json和数组格式的方法详解
2014/01/09 Javascript
为jquery的ajaxfileupload增加附加参数的方法
2014/03/04 Javascript
js 与 php 通过json数据进行通讯示例
2014/03/26 Javascript
javascript动态创建及删除元素的方法
2014/12/22 Javascript
Bootstrap布局方式详解
2016/05/27 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
vue-music关于Player播放器组件详解
2017/11/28 Javascript
vue实现页面内容禁止选中功能,仅输入框和文本域可选
2019/11/09 Javascript
用ReactJS和Python的Flask框架编写留言板的代码示例
2015/12/19 Python
python异常和文件处理机制详解
2016/07/19 Python
wxpython中Textctrl回车事件无效的解决方法
2016/07/21 Python
详解Django中六个常用的自定义装饰器
2018/07/04 Python
把JSON数据格式转换为Python的类对象方法详解(两种方法)
2019/06/04 Python
简单了解python关系(比较)运算符
2019/07/08 Python
如何基于Python制作有道翻译小工具
2019/12/16 Python
如何用python处理excel表格
2020/06/09 Python
详解canvas绘制多张图的排列顺序问题
2019/01/21 HTML / CSS
《童趣》教学反思
2014/02/19 职场文书
交通安全标语
2014/06/06 职场文书
植物园观后感
2015/06/11 职场文书
高二英语教学反思
2016/03/03 职场文书
Apache压力测试工具的安装使用
2021/03/31 Servers
html中两种获取标签内的值的方法
2022/06/10 HTML / CSS