Django Haystack + jieba 实现站内全文检索与关键词高亮


发布时间:2019-02-24 06:51    作者: 晖哥哥   已过去:4 年,1 月   阅读总量:2612 已被赞:7


django-haystack 是一个专门提供搜索功能的 django 第三方应用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多种搜索引擎,配合著名的中文自然语言处理库 jieba 分词,就可以为我们的博客提供一个效果不错的博客文章搜索系统。

实现步骤:

第一步:在项目环境下安装需要的包

pip install whoosh django-haystack jieba

直接一次性安装完成这三个包。

第二步:在项目的 settings.py 做一些简单的配置

1.

INSTALLED_APPS = [
   ...
    'django.contrib.staticfiles',
    'haystack',
   ...
]

2.在settings.py 页面最后加入:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'apps.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'

说明:(因为我们的文章都在blog这个APP下,所以就给blog这个APP添加搜索)

HAYSTACK_CONNECTIONS 的 ENGINE 指定了 django haystack 使用的搜索引擎,这里我们使用apps. blog.whoosh_cn_backend.WhooshEngine,apps.blog是我的项目下apps包下的blog这个APPPATH 指定了索引文件需要存放的位置,我们设置为项目根目录 BASE_DIR 下的 whoosh_index 文件夹(在建立索引是会自动创建)。

HAYSTACK_SEARCH_RESULTS_PER_PAGE 指定如何对搜索结果分页,这里设置为每 10 项结果为一页。

HAYSTACK_SIGNAL_PROCESSOR 指定什么时候更新索引,这里我们使用 haystack.signals.RealtimeSignalProcessor,作用是每当有文章更新时就更新索引。由于博客文章更新不会太频繁,因此实时更新没有问题。

第三步:在 blog 应用下建立一个 search_indexes.py 文件,写上如下代码:(因为我们的文章都在blog这个APP下,所以就给blog这个APP添加搜索)

from haystack import indexes
from .models import Post

class PostIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        return Post

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

说明:

这是 django haystack 的规定。要相对某个 app 下的数据进行全文检索,就要在该 app 下创建一个 search_indexes.py 文件,然后创建一个 XXIndex 类(XX 为含有被检索数据的模型,如这里的 Post),并且继承 SearchIndex 和 Indexable

我们需要为指定的数据添加一个索引(目录),在这里是为 Post 创建一个索引,索引的实现细节是我们不需要关心的,我们只关心为哪些字段创建索引,如何指定。

每个索引里面必须有且只能有一个字段为 document=True,这代表 django haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。注意,如果使用一个字段设置了document=True,则一般约定此字段名为text,这是在 SearchIndex 类里面一贯的命名,以防止后台混乱,当然名字你也可以随便改,不过不建议改。

第四步:指定索引的字段 (templates/search/indexes/  这三个是固定的)

存放索引字段的模板的路径为 templates/search/indexes/你的APP名字/你的模型名字_text.txt(例如 templates/search/indexes/blog/post_text.txt),其内容为:

去到templates/search/indexes/blog/post_text.txt 里写入:

{{object.title}}
{{object.context}}

第五步:配置URL

1.在总路由里加入以下URL:

path('search/', include('haystack.urls')),

2.如果你前面有哪个路由也是使用了search/,请一定先去删除或改掉,避免冲突报错

第六步:修改一下搜索表单,让它提交数据到 django haystack 搜索视图对应的 URL:

1. action="{% url 'haystack_search' %}"

2.name="q"(必须q)

完整代码:

<form class="navbar-form navbar-left" method="get" action="{% url 'haystack_search' %}" >
  <div class="form-group">
    <input type="text" class="form-control" placeholder="站内搜" name="q">
  </div>
     <button type="submit" class="btn btn-default" style="top: 5%">搜一搜</button>
</form>

第七步:创建搜索结果显示页面

因为haystack_search 视图函数会将搜索结果传递给模板 search/search.html,(默认固定)因此创建这个模板文件,对搜索结果进行渲染:

路径:templates/search/search.html

代码:

{% extends 'base1.html' %}
{% load highlight %}
{% block title %}
博文搜索结果页
{% endblock %}
{% block main %}
     <div class="header-banner">
        <div class="container">
            <h1>搜索结果</h1>
            <p>本页面为<span class="hidden-xs">本博客</span>关于{{ fenlei.name }}的全部搜索结果</p>
            <p>huigege|2019</p>
            <form class="navbar-form navbar-collapse" method="get" action="{% url 'haystack_search' %}">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="站内搜" name="q">
             <input type="submit" class="btn btn-default" style="top:5%">
        </div>
      </form>
        </div>
    </div>
<div class="container">
   {% if query %}
    {% for result in page.object_list %}

        <div class="media" style="overflow: hidden">
            <hr>
            <div class="media-left media-middle">
    <a href="#">
      <img class="media-object" src="{{ MEDIA_URL }}{{ result.object.img }}" alt="..." style="width: 120px;height: 120px">
    </a>
  </div>
            <div class="media-body">
            <h4 class="media-heading"><a href="{% url 'blog:post_read' result.object.pk %}" style="color:#333">{% highlight result.object.title with query %}</a></h4>
            <p class="blog-post-meta">发布时间:{{ result.object.put_in_time|date:"Y-m-d"}}&nbsp;&nbsp;&nbsp;
                作者:{{ result.object.author.username }} &nbsp;&nbsp;点赞量:{{ result.object.vote|default_if_none:0 }}</p>
            <p >{% highlight result.object.context with query %}</p>
{#            <p >{{ result.object.context|striptags|truncatechars:300|safe }}</p>#}
            </div>
        </div><!-- /.blog-post -->
        {% empty %}
        <p>未搜索到任何有关文章</p>
    {% endfor %}
    {% else %}
        请输入搜索关键词,例如 django
    {% endif %}
{% if page.has_previous or page.has_next %}
            <div>
                {% if page.has_previous %}
                    <a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; 上一页
                {% if page.has_previous %}</a>{% endif %}
                |
                {% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页
                &raquo;{% if page.has_next %}</a>{% endif %}
            </div>
        {% endif %}
</div>
{% endblock %}

说明:加载{% load highlight %} 是为了高亮关键字,因为haystack_search只会返回一个page变量,我们要拿到内容,就需要遍历他,遍历的格式为

{% for result in page.object_list %}

显示当中的字段,要这样:

{{ result.object.img }}  object不能少。

高亮的字段就长这样:

{% highlight result.object.title with query %} 中间不能再加入其它的过滤器了

在base.html里设置高亮字段的颜色,这里设成红色:

<head>
    <title>Black &amp; White</title>
    ...
    <style>
        span.highlighted {
            color: red;
        }
    </style>
    ...
</head>

 

分页:

{% if page.has_previous or page.has_next %}

<div> {% if page.has_previous %} <a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; 上一页 {% if page.has_previous %}</a>{% endif %} | {% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页 &raquo;{% if page.has_next %}</a>{% endif %} </div>

{% endif %} </div>

高亮显示进一步说明:

注意到百度的搜索结果页面,含有用户搜索的关键词的地方都是被标红的,在 django haystack 中实现这个效果也非常简单,只需要使用 {% highlight %} 模板标签即可,其用法如下:

# 使用默认值  
{% highlight result.summary with query %}  

# 这里我们为 {{ result.summary }} 里所有的 {{ query }} 指定了一个<div></div>标签,并且将class设置为highlight_me_please,这样就可以自己通过CSS为{{ query }}添加高亮效果了,怎么样,是不是很科学呢  
{% highlight result.summary with query html_tag "div" css_class "highlight_me_please" %}  

# 可以 max_length 限制最终{{ result.summary }} 被高亮处理后的长度
{% highlight result.summary with query max_length 40 %}  

在博客文章搜索页中我们对 title 和 body 做了高亮处理:{% highlight result.object.title with query %},{% highlight result.object.body with query %}。高亮处理的原理其实就是给文本中的关键字包上一个 span 标签并且为其添加 highlighted 样式(当然你也可以修改这个默认行为,具体参见上边给出的用法)。

第八步:将jieba设置成默认分词系统

在blog这个APP下(你需要搜索哪个APP下),新建一个whoosh_cn_backend.py

里面的代码如下:请直接下载就行,不需要改动什么,代码下载

第九步:

最后一步就是建立索引文件了,运行命令 python manage.py rebuild_index 就可以建立索引文件了。

来看看搜搜效果吧,效果还不错。

 

点赞

7




登陆后方可评论