Django实现haystack和whoosh实现全局搜索的采坑之旅

haystack接口+Whoosh引擎后端实现搜索详解:

1.为什么选择使用搜索引擎?

目前基本所有的网站都有搜索功能,过去主要是通过模糊查询like,但是like的效率不过,特别是针对关键字在多个字段中搜索的时候,很麻烦,而且在数据量特别大的时候,会给数据库带来特别大的压力,因此我们选择使用搜索引擎来处理。

2.搜索引擎工作原理

搜索引擎的工作原理并不是直接在数据库中进行搜索,而是先对数据库的数据进行一边预处理,建立一份索引结构数据。这样以后搜索的时候,将直接在索引结构数据中搜索关键字,进而找到真实的存储位置,大大提高了效率,减小数据库的压力。

3.如何使用ElasticSearch?

①安装django对接Whoosh的接口haystack包

pip install django-haystack

pip install drf-haystack # 类似drf规则的借口

pip install jieba # 中文分词包

pip install whoosh # 纯python编写的全文搜索引擎,虽然性能不高,但错误少。

如果python版本过高,drf-haystack会自动降低你的版本为django2.2,之前的项目为django3.0不过降低到2.2,只要不涉及wsgi的问题就都没关系。

注:django-haystackhaystack会冲突,报错

from haystack import connections

ImportError: cannot import name 'connections'

因此需要删掉haystack


②将app添加到INSTALLED_APP中

`python
INSTALLED_APPS = [

'simpleui',  

'django.contrib.admin',  

'django.contrib.admindocs',  

'django.contrib.auth',  

'django.contrib.contenttypes',  

'django.contrib.sessions',  

'django.contrib.messages',  

'django.contrib.staticfiles',  

'django.contrib.humanize',  # 人性化标签  

'haystack',  

`


③添加haystack的搜索引擎

这个地方根据官方文档的介绍,有多种全文搜索引擎

(1).这是一种基于elasticserach的搜索引擎

1
2
3
4
5
6
7
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': 'http://127.0.0.1:9200/', # 指定运行搜索引擎的服务器ip地址
'INDEX_NAME': 'haystack', # 指定elasticsearch所建立的索引库的名字
},
}

(2).这是一种基于Whoosh的搜索引擎,这个引擎是纯python写的,速度虽然没有elasticsearch等搜索引擎快,但是报错少呀~

1
2
3
4
5
6
7
8
HAYSTACK_CONNECTIONS = {
'default': {
# 指定使用的搜索引擎
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
# 指定索引文件存放位置
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}

如果需要同步更新索引,添加如下配置:

1
2
# 新增的数据自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

如果需要设置每页显示的数目,因为它同时内置了django的分页器功能,添加如下配置:

1
2
# 设置每页显示的数目,默认为20,可以自己修改
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 6

④添加SerachIndexes

SerachIndex对象指的是应该在搜索索引中放置什么样的数据和怎样处理数据流的一个对象。

其次我们需要子类化indexs.SearchIndex和indexes.Indexable类。

包含get_model()获取模型方法,以及定义查询关键字的index_queryset()方法。

注:该py最好放在要搜索的model的app下。因为haystack会自动进行搜索。

在自己的app下创建py文件,search_indexes.py(注意名称固定,方便haystack查找到)不要随意替换目录!

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class NoteIndex(indexes.SearchIndex, indexes.Indexable):
"""
定义关于Note的haystack搜索引擎
"""
# document 表示该字段主要用于关键字查询的主要字段
# use_Template表示该字段将从模板中指明
text = indexes.CharField(document=True, use_template=True)
# model_attr表明能让搜索引擎识别的额外字段,用来检索参照数据表中的字段值
title = indexes.CharField(model_attr='title')
note_author = indexes.CharField(model_attr='note_author')

def get_model(self):
# 返回建立索引的模型类
return Note

def index_queryset(self, using=None):
# 返回建立索引的数据查询集
return self.get_model().note_.all()

这里稍微说明一下:

1.搜索引擎要查找对应的数据肯定需要关键字,而这个关键字可能有多个,所以text字段代表了这些关键字,

2.document=True必须出现在主关键字中

3.use_template=True,需要新建一个txt文档来存放索引关键字。

4.model_attr标记的关键字,用作额外关键字。


⑤创建搜索引擎文档:

名命格式:templates/search/indexes/<appname>/<model>_text.txt

写入以下内容索引字段

1
2
3
4
{{ object.id }}
{{ object.title }}
{{ object.note_author.username }}
{{ object.type }}

作用是构建搜索引擎所索引的文档,其中text字段的索引值可以由多个字段组成,具体由哪些模型类字段组成,将存在于搜索引擎文档中。

例如我这里的关键字字段有4个,那么转化为url的时候,这些关键字将通过text参数名传递此模板指明当将关键词通过text参数名传递时

(即127.0.0.1:8080/notes/search/?text=2

或127.0.0.1:8080/goods/search/?text=’syz’

或127.0.0.1:8080/goods/search/?text=’python笔记(1)’

或127.0.0.1:8080/goods/search/?text=’celery类别’

可以通过Note(model)的id、title、note_author.username、type来进行关键字索引查询。


⑥最后别忘了添加url路由

1
path('search/', include('haystack.urls')),
1
2
3
4
5
from django.conf.urls import url
from haystack.views import SearchView
urlpatterns = [
url(r'^$', SearchView(), name='haystack_search'),
]

说明:include(haystack.urls)实际是include第二种子urlpatterns


⑦使用中文分词包jieba进行词组分析

因为whoosh默认使用的分词功能依赖于正侧表达式,所以对英文的分词比较有用,但是对于中文分词效果不好。因此我们就需要一个具备中文字典的分词包—-jieba。

jieba的关键词提取主要运用了两种算法:texttank,TF-IDF。这里超出了本篇笔记的范围,暂时不做介绍。(主要是作者我深入接触哈哈哈)

使用jieba作为分词包,我们就需要修改whoosh的后端。

找到site-packages中的whoosh_backend.py

修改配置:

1
2
3
4
5
6
#import最后一行加入jieba分词器
from jieba.analyse import ChineseAnalyzer

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)
# 将analyzer替换成jieba的ChineseAnalyzer

以上基本的配置及搜索索引已经搭建好,接下来就需要生成索引表了


⑧手动更新索引:

python manage.py rebuild_index # 更新数据库的数据到es中


⑨搭配restful api 传递数据

做下一个项目的时候完善这里


详情参考haystack官方文档:
https://django-haystack.readthedocs.io/en/v2.5.1/tutorial.html