博客使用Haystack实现全文搜索
在搭建博客的过程中, 随着博客的数量越来越多, 不可避免的用到搜索功能. 同时为了方便用户快速找到感兴趣的相关内容, 也需要添加一个站内搜索功能. django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多种搜索引擎,配合著名的中文自然语言处理库 jieba 分词,就可以为我们的博客提供一个效s果不错的博客文章搜索系统。
安装
- Whoosh. 一个由Python实现的全文搜索引擎
- jieba 中文分词
- django-haystack
pip install whoosh django-haystack jieba
配置
首先是把 django haystack 加入到 INSTALLED_APPS 选项里:
INSTALLED_APPS = [
'django.contrib.admin',
# 其它 app...
'haystack',
'blog',
'comments',
]
添加如下选项
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'blog.whoosh_cn_backend.WhooshEngine',
'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
},
}
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
这里的whoosh_cn_backend
需要在对应的app下面创建; HAYSTACK_SEARCH_RESULTS_PER_PAGE
指明每页的搜索结果数量; HAYSTACK_SIGNAL_PROCESSOR
指明更新文章的时机, 这里选择每当有新文章的时候更新索引, 由于博客不会频繁添加删除, 所以这种实时更新索引可以接受.
搜索文件建立
这里需要新建一个文件, search_indexes.py
用来说明应该使用哪些数据来建立索引. 针对博客来说, 需要建立索引的是blog这个应用下的Blog模型. 故相应的详情如下:
from haystack import indexes
from .models import Blog
class BlogIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
return Blog
def index_queryset(self, using=None):
return self.get_model().objects.all()
注意:
- 每个索引里面必须有且只能有一个字段为 document=True
-
use_template=True
允许我们使用数据模板去建立搜索引擎索引的文件. 数据模板的路径为templates/search/indexes/youapp/\<model_name>_text.txt
这里创建博客的数据模板为:
templates/search/indexes/blog/blog_text.txt
{{ object.title }}
{{ object.content }}
这里说明使用title和content两个字段的内容对博客进行全文索引.
配置url
在项目的主url文件中添加如下url
path('search/', include('haystack.urls'))
配置whoosh_cn_backend
在blog下新建一个文件 whoosh_cn_backend.py
, 将
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)
将其中的analyzer修改为中文分词:
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(), field_boost=field_class.boost, sortable=True)
添加搜索表单
这里选择在base.html
文件中添加一个搜索框, 这样所有的页面都能共享到这个搜索框了
<form action="{% url 'haystack_search' %}" class="navbar-form navbar-right" method="get">
<input name="q" type="text" placeholder="搜索博文" class="form-control">
<button type="submit">
<span class="glyphicon glyphicon-search"></span>
</button>
</form>
action为 {% url 'haystack_search' %}
指明了搜索使用的是haystack
的url.
获得搜索结果
haystack的搜索结果返回给 search/search.html
, 需要先创建这个文件.
{% extends 'base.html' %}
{% load highlight %}
{% load comment_tags %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-sm-8 col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">{% block block_list_title %}博客列表{% endblock %}</div>
<div class="panel-body">
{% if query %}
{% for blog in page.object_list %}
<div class="blog">
<h3>
<a href="{% url 'blog_detail' blog.object.pk %}">
{{ blog.object.title }}
</a>
</h3>
<p class="blog-info">
{% for tag in blog.object.tags.all %}
<span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
<a href="{% url 'blogs_with_tag' tag.pk %}">
{{ tag.name }}
</a>
{% endfor %}
<span class="glyphicon glyphicon-time" aria-hidden="true"></span>{{ blog.object.created_time|date:"Y-m-d" }}
阅读({{ blog.object.get_read_num }})
评论({% get_comment_count blog.object %})
</p>
</div>
<div class="entry-content clearfix">
<p>{% highlight blog.object.content with query %}</p>
</div>
{% empty %}
<div class="blog">
<h3>没有搜索到你想要的结果!</h3>
</div>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}
<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« 上一页
{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}下一页
»{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}
请输入搜索关键词,例如 django
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}
如果是搜索的内容, 还想要对搜索的原始文本进行高亮, 所以这里添加了如下代码
<div class="entry-content clearfix">
<p>{% highlight blog.object.content with query %}</p>
</div>
完成