Django中使用haystack+whoosh实现搜索功能


Posted in Python onOctober 08, 2019

为了实现项目中的搜索功能,我们使用的是全文检索框架haystack+搜索引擎whoosh+中文分词包jieba

安装和配置

安装所需包

pip install django-haystack
pip install whoosh
pip install jieba

去settings文件注册haystack应用

INSTALLED_APPS = [
 'haystack', # 注册全文检索框架
]

在settings文件中配置全文检索框架

# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
 'default': {
  # 使用whoosh引擎
  'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
  # 索引文件路径
  'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
 }
}

# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

索引文件的生成

要生成索引文件,首先你要配置,对哪些内容进行索引,比如商品名称,简介和详情;为了配置对数据库指定内容进行索引,我们要做如下步骤:

配置search_indexes.py文件

因为在django中数据库一般都是通过ORM生成的,首先我们在要在数据表对应的应用中创建一个 search_indexes.py 文件,例如,我现在要检索商品对应的表就是GoodsSKU表,而表是在goods应用下的,所以我在goods应用下新建 search_indexes.py 文件,截图如下:

Django中使用haystack+whoosh实现搜索功能

在 search_indexes.py 文件中加入以下内容

# 定义索引类
from haystack import indexes
# 导入你的模型类
from goods.models import GoodsSKU
# 指定对于某个类的某些数据建立索引
# 索引类名格式:模型类名+Index
class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):
 # 索引字段 use_template=True指定根据表中的哪些字段建立索引文件的说明放在一个文件中
 text = indexes.CharField(document=True, use_template=True)
 def get_model(self):
  # 返回你的模型类
  return GoodsSKU
 # 建立索引的数据
 def index_queryset(self, using=None):
  return self.get_model().objects.all()

指定要检索的内容

在templates文件夹下面新建search文件夹,在search文件夹下面新建indexes文件夹,在indexes文件夹下面新建要检索应用名的文件夹比如goods文件夹,在goods文件夹下面新建 表名_text.txt,表名小写,所以目前的目录结构是这样的 templates/search/indexes/goods/goodssku_text.txt ,截图如下:

Django中使用haystack+whoosh实现搜索功能

在goodssku_text.txt 文件中指定你要根据表中的哪些字段建立索引数据,现在我们要根据商品的名称,简介,详情来建立索引,如下配置

# 指定根据表中的哪些字段建立索引数据
{{ object.name }} # 根据商品的名称建立索引
{{ object.desc }} # 根据商品的简介建立索引
{{ object.goods.detail }} # 根据商品的详情建立索引

其中的objects可以理解为数据表对应的商品对象。

生成索引文件

使用pycharm自带的命令行terminal运行以下命令生成索引文件:

python manage.py rebuild_index

运行成功后,你可以在项目下看到类似如下索引文件

Django中使用haystack+whoosh实现搜索功能

使用全文检索

通过如上的配置,我们的数据索引已经建立了,现在我们要在项目中使用全文检索。

在需要使用检索的地方进行 form 表单改造

<form action="/search" method="get">
 <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
 <input type="submit" class="input_btn fr" name="" value="搜索">
</form>

如上所示,其中要注意的是:

发送方式必须使用get;

搜索的input框 name 必须是 q;

配置检索对应的url

在项目下的urls.py文件中添加如下url配置

urlpatterns = [
 url(r'^search/', include('haystack.urls')), # 全文检索框架
]

检索成功后生成的参数

当haystack自动检索成功后,会给我们返回三个参数;

query参数,表示你查询的参数;

page参数,当前页的Page对象,是查询到的对象的集合,可以通过for循环类获取单个商品,通过 商品.objects.xxx 获取商品对应的字段;

paginator参数,分页paginator对象。

可以通过如下代码测试参数

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
搜索的关键字:{{ query }}<br/>
当前页的Page对象:{{ page }}<br/>
<ul>
 {% for item in page %}
  <li>{{ item.object }}</li>
 {% endfor %}
</ul>
分页paginator对象:{{ paginator }}<br/>
</body>
</html>

templates/indexes/search.html

注意,位置和文件名都是固定的,并且这只是测试文件,后面使用全文检索时记得不能使用search.html,改成其他名字。

数据+search.html返回渲染后页面

当haystack全文检索后会返回数据,现在我们需要一个页面来接收这些数据,并且在页面渲染后返回这个页面给用户观看,渲染并返回页面的工作haystack已经帮我们做了,那么我们现在只需要准备一个页面容纳数据即可。

在templates文件夹下的indexes文件夹下新建一个search.html,注意路径和文件名是固定的,如下图

Django中使用haystack+whoosh实现搜索功能

利用检索返回的参数在search.html中定义要渲染出的模板和样式,我的页面如下

<div class="breadcrumb">
 <a href="#">{{ query }}</a>
 <span>></span>
 <a href="#">搜索结果如下:</a>
</div>
<div class="main_wrap clearfix">
 <ul class="goods_type_list clearfix">
  {% for item in page %}
  <li>
   <a href="{% url 'goods:detail' item.object.id %}"><img src="{{ item.object.image.url }}"></a>
   <h4><a href="{% url 'goods:detail' item.object.id %}">{{ item.object.name }}</a></h4>
   <div class="operate">
    <span class="prize">¥{{ item.object.price }}</span>
    <span class="unit">{{ item.object.price}}/{{ item.object.unite }}</span>
    <a href="#" class="add_goods" title="加入购物车"></a>
   </div>
  </li>
  {% endfor %}
 </ul>
 <div class="pagenation">
   {% if page.has_previous %}
   <a href="/search?q={{ query }}&page={{ page.previous_page_number }}"><上一页</a>
   {% endif %}
   {% for pindex in paginator.page_range %}
    {% if pindex == page.number %}
     <a href="/search?q={{ query }}&page={{ pindex }}" class="active">{{ pindex }}</a>
    {% else %}
     <a href="/search?q={{ query }}&page={{ pindex }}">{{ pindex }}</a>
    {% endif %}
   {% endfor %}
   {% if page.has_next %}
   <a href="/search?q={{ query }}&page={{ page.next_page_number }}">下一页></a>
   {% endif %}
  </div>
</div>

search.html

至此,我们可以在页面上搜索一下内容,应该是能成功的,但也有可能不会返回任何数据就算name就是你搜索的内容,这是因为我们现在使用的主要还是为英语服务的分词包,接下来我们要配置使用中文分词包了。

使用中文分词包jieba

在前面的配置中我们已经安装了jieba;

创建 ChineseAnalyzer.py 文件

进入虚拟环境下的 Lib\site-packages\haystack\backends 目录下新建 ChineseAnalyzer.py 文件

目录如下图

Django中使用haystack+whoosh实现搜索功能

在文件中添加如下内容

import jieba
from whoosh.analysis import Tokenizer, Token
class ChineseTokenizer(Tokenizer):
 def __call__(self, value, positions=False, chars=False,
     keeporiginal=False, removestops=True,
     start_pos=0, start_char=0, mode='', **kwargs):
  t = Token(positions, chars, removestops=removestops, mode=mode,
     **kwargs)
  seglist = jieba.cut(value, cut_all=True)
  for w in seglist:
   t.original = t.text = w
   t.boost = 1.0
   if positions:
    t.pos = start_pos + value.find(w)
   if chars:
    t.startchar = start_char + value.find(w)
    t.endchar = start_char + value.find(w) + len(w)
   yield t
def ChineseAnalyzer():
 return ChineseTokenizer()

ChineseAnalyzer.py

编写haystack可使用的 whoosh_cn_backend.py 文件

直接在 虚拟环境下的 Lib\site-packages\haystack\backends 目录下复制一份 whoosh_backend.py 文件 并且重命名复制文件为 whoosh_cn_backend.py;

在 whoosh_cn_backend.py 中导入我们编写的 ChineseAnalyzer 类

from .ChineseAnalyzer import ChineseAnalyzer

更改haystack使用的分词包为 jieba 编写的中文分词类,大概在第160行左右

# schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)

配置whoosh引擎使用 whoosh_cn_backend.py

在settings文件中更改原来的配置如下

# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
 'default': {
  # 使用whoosh引擎
  # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
  'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
  # 索引文件路径
  'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
 }
}
# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

重新生成索引文件

python manage.py rebuild_index

至此,就可以放心的使用搜索功能了,如图,搜索成功的显示页面

Django中使用haystack+whoosh实现搜索功能

可以通过如下配置控制每个分页显示的搜索出来对象的数目

# 指定搜索结果每页显示的条数
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 1

总结

以上所述是小编给大家介绍的Django之使用haystack+whoosh实现搜索功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
python利用sklearn包编写决策树源代码
Dec 21 Python
浅谈Python使用Bottle来提供一个简单的web服务
Dec 27 Python
Python实现按当前日期(年、月、日)创建多级目录的方法
Apr 26 Python
对python中array.sum(axis=?)的用法介绍
Jun 28 Python
如何在django里上传csv文件并进行入库处理的方法
Jan 02 Python
python在回调函数中获取返回值的方法
Feb 22 Python
浅谈Python小波分析库Pywavelets的一点使用心得
Jul 09 Python
Pytorch抽取网络层的Feature Map(Vgg)实例
Aug 20 Python
关于Keras模型可视化教程及关键问题的解决
Jan 24 Python
python实现ftp文件传输系统(案例分析)
Mar 20 Python
python怎么调用自己的函数
Jul 01 Python
理解Django 中Call Stack机制的小Demo
Sep 01 Python
python 使用while写猜年龄小游戏过程解析
Oct 07 #Python
python getpass模块用法及实例详解
Oct 07 #Python
Python拆分大型CSV文件代码实例
Oct 07 #Python
Python模块汇总(常用第三方库)
Oct 07 #Python
python numpy之np.random的随机数函数使用介绍
Oct 06 #Python
python系列 文件操作的代码
Oct 06 #Python
pip 安装库比较慢的解决方法(国内镜像)
Oct 06 #Python
You might like
PHP中file_exists()判断中文文件名无效的解决方法
2014/11/12 PHP
php自定义函数实现二维数组排序功能
2016/07/20 PHP
ThinkPHP框架实现的MySQL数据库备份功能示例
2018/05/24 PHP
Extjs学习笔记之六 面版
2010/01/08 Javascript
浅析JS刷新框架中的其他页面 &amp;&amp; JS刷新窗口方法汇总
2013/07/08 Javascript
javascript中的nextSibling使用陷(da)阱(keng)
2014/05/05 Javascript
跟我学习javascript的call(),apply(),bind()与回调
2015/11/16 Javascript
js获取Get值的方法
2016/09/29 Javascript
jquery实现tab键进行选择后enter键触发click行为
2017/03/29 jQuery
详解 vue.js用法和特性
2017/10/15 Javascript
微信小程序实现自定义加载图标功能
2018/07/19 Javascript
webpack4+react多页面架构的实现
2018/10/25 Javascript
JS计算两个数组的交集、差集、并集、补集(多种实现方式)
2019/05/21 Javascript
功能完善的小程序日历组件的实现
2020/03/31 Javascript
[02:12]打造更好的电竞完美世界:完美盛典回顾篇
2018/12/19 DOTA
Python实现网站文件的全备份和差异备份
2014/11/30 Python
对python自动生成接口测试的示例讲解
2018/11/30 Python
PyQt5通信机制 信号与槽详解
2019/08/07 Python
Python 写了个新型冠状病毒疫情传播模拟程序
2020/02/14 Python
python实现ftp文件传输功能
2020/03/20 Python
利用python实现平稳时间序列的建模方式
2020/06/03 Python
python基于pexpect库自动获取日志信息
2021/02/01 Python
纽约州一群才华横溢的金匠制作而成:Hearth Jewelry
2019/03/22 全球购物
阿里巴巴的Oracle DBA笔试题答案-SQL tuning类
2016/04/03 面试题
银行实习自我鉴定
2013/10/12 职场文书
学校消防安全责任书
2014/07/23 职场文书
园艺专业毕业生求职信
2014/09/02 职场文书
回复函格式及范文
2015/07/14 职场文书
《平移和旋转》教学反思
2016/02/19 职场文书
高中政治教学反思
2016/02/23 职场文书
2019数学教师下学期工作总结
2019/06/27 职场文书
关于食品安全的演讲稿范文(三篇)
2019/10/21 职场文书
Python趣味挑战之教你用pygame画进度条
2021/05/31 Python
Java并发编程之Executor接口的使用
2021/06/21 Java/Android
Vue实现tab导航栏并支持左右滑动功能
2021/06/28 Vue.js
react中的DOM操作实现
2021/06/30 Javascript