Django学习笔记(四十五):haystack全文检索框架+whoosh搜索引擎+jieba分词实现全文检索功能
全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理。
- haystack:全文检索的框架,支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎,点击查看官方网站。
- whoosh:纯Python编写的全文搜索引擎,虽然性能比不上sphinx、xapian、Elasticsearc等,但是无二进制包,程序不会莫名其妙的崩溃,对于小型的站点,whoosh已经足够使用,点击查看whoosh文档。
- jieba:一款免费的中文分词包,如果觉得不好用可以使用一些收费产品。
1)在虚拟环境中依次安装需要的包。
pip install django-haystack
pip install whoosh
pip install jieba
2)修改settings.py文件,安装应用haystack。
INSTALLED_APPS = (
...
'haystack',
)
3)在settings.py文件中配置搜索引擎。
...
HAYSTACK_CONNECTIONS = {
'default': {
#使用whoosh引擎
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
#索引文件路径
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}
# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 指定搜索结果每页显示的条数
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 1
4)在相应的app目录中添加搜索的配置,文件名必须为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()
5)在templates目录添加search子目录,search子目录下添加indexes子目录,indexes子目录下添加app同名称的子目录goods,goods子目录下添加所需索引模型名小写goodssku_text.txt,以上名称均为固定格式,在goodssku_text.txt添加需要索引的字段


6)建立索引数据,并在whoosh_index文件中生成索引文件
python manage.py rebuild_index


7)页面中的搜索框的一些固定需求,请求方式为get,搜索的别名为q
<div class="search_con fl">
<form method="get" action="/search">
<input type="text" class="input_text fl" name="q" placeholder="搜索商品">
<input type="submit" class="input_btn fr" name="" value="搜索">
</form>
</div>
8)在项目的urls.py中添加search的路由配置
url(r'^search', include('haystack.urls')), # 全文检索框架
9)使用搜索功能搜索出的结果数据,haystack会将数据返回到templates下面的sreach目录下的sreach.html中

haystack传递的上下文信息包括:
query:搜索的关键字
page:当前页的page对象,遍历page对象,获得到的是SearchResult类的实例对象,对象的属性obje才是模型类的对象
paginator:分页paginator对象
<body>
query:{{ query }}<br>
page:{{ page }}<br>
{% for item in page %}
{{ item.object }}
{% endfor %}<br>
paginator:{{ paginator }}<br>
</body>

10)按照开发需求新建search.html文件
{% extends 'base_detail_list.html' %}
{% block title %}天天生鲜-商品搜索结果列表{% endblock title %}
{% block main_content %}
<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 spage.has_next %}
<a href="/search?q={{ query }}&page={{ page.next_page_number }}">下一页></a>
{% endif %}
</div>
</div>
{% endblock main_content %}

全文检索到现在算完成了大半,现在还有一个问题就是查找出来的数据并不完整,如图可见,盒装草莓并没有被搜索出来,原因是因为whoosh默认的引擎对中文分词的效果不是很好,导致它无法将一些词语进行分词搜索出来。

11)所以我们使用jieba中文分词的包,使他有更好的中文分词效果


12)项目中结合whoosh的使用方法,修改默认的whoosh_backend,找到你下载的haystack文件路径
Python\Python36\Lib\site-packages\haystack\backends
在该目录下创建ChineseAnalyzer.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 ChineseAnalyzer():
return ChineseTokenizer()
13)在相同目录下创建 whoosh_cn_backend.py文件,内容和whoosh_backend.py基本相同,只是将引用StemmingAnalyzer的地方(有两处)全部改成引用ChineseAnalyzer即可
from .ChineseAnalyzer import ChineseAnalyzer
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)
if highlight:
sa = ChineseAnalyzer()
14)重新修改setting.py里的haysatck配置
# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
'default': {
# 使用whoosh引擎
'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
# 索引文件路径
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
}
}
15)重新创建索引,可以看到已使用jieba分词进行索引

16)重新搜索关键词看是否达到效果

