django搜索 關鍵字 全文檢索haystack 搜索分詞數據庫

Django Haystack 簡介

django-haystack 是一個專門提供搜索功能的 django 第三方應用,它支持 Solr、Elasticsearch、Whoosh、Xapian 等多種搜索引擎,配合中文自然語言處理庫 jieba 分詞,就可以爲博客提供博客文章搜索系統。

安裝必要依賴

  • Whoosh。Whoosh 是一個由純 Python 實現的全文搜索引擎,沒有二進制文件等,比較小巧,配置簡單方便。
  • jieba 中文分詞。由於 Whoosh 自帶的是英文分詞,對中文的分詞支持不是太好,所以使用 jieba 替換Whoosh 的分詞組件。

pip install whoosh django-haystack jieba

配置 Haystack

安裝好 django haystack 後需要在項目的 settings.py 做一些簡單的配置。

首先是把 django haystack 加入到 INSTALLED_APPS 選項裏:

複製代碼

blogproject/settings.py

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'

複製代碼

HAYSTACK_CONNECTIONS 的 ENGINE 指定了 django haystack 使用的搜索引擎,這裏我們使用了 blog.whoosh_cn_backend.WhooshEngine,雖然目前這個引擎還不存在,但我們接下來會創建它。PATH 指定了索引文件需要存放的位置,我們設置爲項目根目錄 BASE_DIR 下的 whoosh_index 文件夾(在建立索引是會自動創建)。

HAYSTACK_SEARCH_RESULTS_PER_PAGE 指定如何對搜索結果分頁,這裏設置爲每 10 項結果爲一頁。

HAYSTACK_SIGNAL_PROCESSOR 指定什麼時候更新索引,這裏我們使用haystack.signals.RealtimeSignalProcessor,作用是每當有文章更新時就更新索引。由於博客文章更新不會太頻繁,因此實時更新沒有問題。

處理數據

接下來就要告訴 django haystack 使用那些數據建立索引以及如何存放索引。如果要對 blog 應用下的數據進行全文檢索,做法是在 blog 應用下建立一個 search_indexes.py 文件,寫上如下代碼:

複製代碼

blog/search_indexes.py

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

每個索引裏面必須有且只能有一個字段爲 document=True,這代表 django haystack 和搜索引擎將使用此字段的內容作爲索引進行檢索(primary field)。注意,如果使用一個字段設置了document=True,則一般約定此字段名爲text,這是在 SearchIndex 類裏面一貫的命名,以防止後臺混亂

並且,haystack 提供了use_template=True 在 text 字段中,這樣就允許我們使用數據模板去建立搜索引擎索引的文件,說得通俗點就是索引裏面需要存放一些什麼東西,例如 Post 的 title 字段,這樣我們可以通過 title 內容來檢索 Post 數據了。舉個例子,假如你搜索 Python ,那麼就可以檢索出 title 中含有 Python 的Post了,怎麼樣是不是很簡單?數據模板的路徑爲 templates/search/indexes/youapp/\<model_name>_text.txt(例如 templates/search/indexes/blog/post_text.txt),其內容爲:

templates/search/indexes/blog/post_text.txt

{{ object.title }}
{{ object.body }}

這個數據模板的作用是對 Post.title、Post.body 這兩個字段建立索引,當檢索的時候會對這兩個字段做全文檢索匹配,然後將匹配的結果排序後作爲搜索結果返回。

配置 URL

接下來就是配置 URL,搜索的視圖函數和 URL 模式 django haystack 都已經幫我們寫好了,只需要項目的 urls.py 中包含它:

複製代碼

blogproject/urls.py

urlpatterns = [
    # 其它...
    url(r'^search/', include('haystack.urls')),
]

複製代碼

另外在此之前我們也爲自己寫的搜索視圖配置了 URL,把那個 URL 刪掉,以免衝突:

blog/urls.py

# url(r'^search/$', views.search, name='search'),

修改搜索表單

修改一下搜索表單,讓它提交數據到 django haystack 搜索視圖對應的 URL:

<form role="search" method="get" id="searchform" action="{% url 'haystack_search' %}">
  <input type="search" name="q" placeholder="搜索" required>
  <button type="submit"><span class="ion-ios-search-strong"></span></button>
</form>

主要是把表單的 action 屬性改爲 {% url 'haystack_search' %}

創建搜索結果頁面

haystack_search 視圖函數會將搜索結果傳遞給模板 search/search.html,因此創建這個模板文件,對搜索結果進行渲染:

複製代碼

templates/search/search.html

{% extends 'base.html' %}
{% load highlight %}

{% block main %}
    {% if query %}
        {% for result in page.object_list %}
            <article class="post post-{{ result.object.pk }}">
                <header class="entry-header">
                    <h1 class="entry-title">
                        <a href="{{ result.object.get_absolute_url }}">{% highlight result.object.title with query %}</a>
                    </h1>
                    <div class="entry-meta">
                    <span class="post-category">
                        <a href="{% url 'blog:category' result.object.category.pk %}">
                            {{ result.object.category.name }}</a></span>
                        <span class="post-date"><a href="#">
                            <time class="entry-date" datetime="{{ result.object.created_time }}">
                                {{ result.object.created_time }}</time></a></span>
                        <span class="post-author"><a href="#">{{ result.object.author }}</a></span>
                        <span class="comments-link">
                        <a href="{{ result.object.get_absolute_url }}#comment-area">
                            {{ result.object.comment_set.count }} 評論</a></span>
                        <span class="views-count"><a
                                href="{{ result.object.get_absolute_url }}">{{ result.object.views }} 閱讀</a></span>
                    </div>
                </header>
                <div class="entry-content clearfix">
                    <p>{% highlight result.object.body with query %}</p>
                    <div class="read-more cl-effect-14">
                        <a href="{{ result.object.get_absolute_url }}" class="more-link">繼續閱讀 <span
                                class="meta-nav">→</span></a>
                    </div>
                </div>
            </article>
        {% empty %}
            <div class="no-post">沒有搜索到你想要的結果!</div>
        {% endfor %}
        {% 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; Previous
                {% if page.has_previous %}</a>{% endif %}
                |
                {% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}Next
                &raquo;{% if page.has_next %}</a>{% endif %}
            </div>
        {% endif %}
    {% else %}
        請輸入搜索關鍵詞,例如 django
    {% endif %}
{% endblock main %}

複製代碼

這個模板基本和 blog/index.html 一樣,只是由於 haystack 對搜索結果做了分頁,傳給模板的變量是一個 page 對象,所以我們從 page 中取出這一頁對應的搜索結果,然後對其循環顯示,即 {% for result in page.object_list %}。另外要取得 Post(文章)以顯示文章的數據如標題、正文,需要從 result 的 object 屬性中獲取。query 變量的值即爲用戶搜索的關鍵詞。

高亮關鍵詞

注意到百度的搜索結果頁面,含有用戶搜索的關鍵詞的地方都是被標紅的,在 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 樣式(當然你也可以修改這個默認行爲,具體參見上邊給出的用法)。因此我們還要給 highlighted 類指定樣式,在 base.html 中添加即可:

複製代碼

base.html

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

複製代碼

修改搜索引擎爲中文分詞

我們使用 Whoosh 作爲搜索引擎,但在 django haystack 中爲 Whoosh 指定的分詞器是英文分詞器,可能會使得搜索結果不理想,我們把這個分詞器替換成 jieba 中文分詞器。從你安裝的 haystack 中把 haystack/backends/whoosh_backends.py 文件拷貝到 blog/ 下,重命名爲 whoosh_cn_backends.py(之前我們在 settings.py 中 的 HAYSTACK_CONNECTIONS 指定的就是這個文件),然後找到如下一行代碼 第164行:

schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=StemmingAnalyzer(), field_boost=field_class.boost, sortable=True)

將其中的 analyzer 改爲 ChineseAnalyzer,當然爲了使用它,你需要在文件頂部引入:from jieba.analyse import ChineseAnalyzer。

複製代碼

from jieba.analyse import ChineseAnalyzer

...
#注意先找到這個再修改,而不是直接添加  
schema_fields[field_class.index_fieldname] = TEXT(stored=True, analyzer=ChineseAnalyzer(),field_boost=field_class.boost, sortable=True)

複製代碼

建立索引文件

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

出現警告選擇y

親測有效

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章