一提起数据库关键搜索,相信大家都会想起like语句,django中也可以使用orm的contains进行查询,这种查询是非常耗时间的,对于小量数量还可以,但随着数据的增多,查询速度会急剧下降,因此网站中使用这种方式是非常不合理的。基于这种情况,许多全文搜索框架应运而生。
本来打算使用haystack+elasticsearch实现全局搜索,但windows的系统环境问题和windows版的docker让我几近崩溃,不得不放弃,我发誓有钱一定要买一台好电脑,起码可以装5个linux虚拟机的那种。
退而求其次,我打算使用haystack+whoosh+jieba实现网站的全局搜索功能,whoosh是一个纯python编写的搜索引擎,虽然速度不及java编写的elasticsearch,solr等,但对与一般的中小项目足够用了,最关键的一点是不用再搞各种java环境了。直接在项目中使用whoosh不是一件容易的事,因此需要用到haystack这个全文搜索框架,官网上说:Haystack为Django提供模块化搜索。它具有统一,熟悉的API,允许您插入不同的搜索后端(如Solr, Elasticsearch,Whoosh,Xapian等),而无需修改代码。whoosh自带的分词工具对于中文来说不是太友好,因此我使用了中文分词还算不错的jieba作为分词工具。
第一步:
安装django-haystack,whoosh,jieba
pip install django-haystack
pip install whoosh
pip install jieba
# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine', # 使用whoosh引擎
'PATH': os.path.join(BASE_DIR, 'whoosh_index'), # 索引文件的路径
},
}
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' # 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10 # 指定搜索结果每页的条数
第二步:
生成索引文件
在包含被索引字段的models.py所在的app下新建一个search_indexes.py,名字固定。
在该py文件里创建索引类
from haystack import indexes
from Store.models import Goods
# 对某个类中的某些数据建立索引
class GoodsIndex(indexes.SearchIndex,indexes.Indexable):
# document=True说明这是一个索引字段,user_template=True表明通过模板来指明索引值由哪些模型类字段组成
text = indexes.CharField(document=True,use_template=True)
def get_model(self):
return Goods # 返回模型类
def index_queryset(self, using=None):
return self.get_model().objects.all() # 返回建立索引的数据
第三步:
创建模板文件
user_template=True表明通过模板来指明索引值由哪些模型字段组成,因此需要创建一个模板文件。
该模板文件要创建在templates下
search和indexes文件夹是固定不变的,Store文件夹和存放search_indexes.py文件的app名字相同,txt文件命名格式:所使用模型类类名小写_text.txt
在该文件下填写想要创建索引的字段,格式{{ objects.字段名 }}
# 指明需要生成索引的字段
{{ object.goods_name }} # 使用商品名称建立索引
{{ object.goods_description }} # 使用商品描述建立索引
{{ object.goods_detail }} # 使用商品详情建立索引
第四步:
建立索引数据
命令行输入python manage.py rebuild_index
第五步:
配置路由
修改前端页面
请求方式为“get”,name为“q”
第六步:
配置jieba分词
在安装的haystack文件下的backends文件夹下新建jiebaanalyzer.py文件。
文件夹里添加如下代码
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 JiebaAnalyzer():
return ChineseTokenizer()
然后备份whoosh_backend.py文件为whoosh_backend_bak.py,在whoosh_backend.py文件中导入新建的jiebaanalyzer.py
然后找到analyzer=StemmingAnalyzer()
,将其改为JiebaAnalyzer()
最后点击保存。
这样jieba分词就配置完成了。
第七步:
重新建立索引数据
此时我们就可以愉快的使用haystack+whoosh+jieba进行全局搜索了。
当我们输入查找关键词后,haystack会使用whoosh进行匹配,并将相关的数据返回给我们。主要有三个数据:
query:搜索关键字
page:当前页的page对象,包含具体的商品信息
paginator:paginator对象
我们只需要将这些数据通过模板语言渲染到前端页面即可。