Django集成搜索引擎Elasticserach

1.背景

當用戶在搜索框輸入關鍵字後,咱們要爲用戶提供相關的搜索結果。能夠選擇使用模糊查詢like關鍵字實現,可是 like 關鍵字的效率極低。查詢須要在多個字段中進行,使用 like 關鍵字也不方便,另外分詞的效果也不理想。javascript

全文檢索方案

  • 全文檢索即在指定的任意字段中進行檢索查詢。html

  • 全文檢索方案須要配合搜索引擎來實現。java

搜索引擎原理

  • 搜索引擎進行全文檢索時,會對數據庫中的數據進行一遍預處理,單獨創建起一份索引結構數據python

  • 索引結構數據相似字典的索引檢索頁,裏面包含了關鍵詞與詞條的對應關係,並記錄詞條的位置。jquery

  • 搜索引擎進行全文檢索時,將關鍵字在索引數據中進行快速對比查找,進而找到數據的真實存儲位置數據庫

2.Elasticsearch介紹

實現全文檢索的搜索引擎,首選的是Elasticsearchapache

  • Elasticsearch 是用 Java 實現的,開源的搜索引擎。django

  • 它能夠快速地儲存、搜索和分析海量數據。維基百科、Stack Overflow、Github等都採用它。後端

  • Elasticsearch 的底層是開源庫 Lucene。可是,無法直接使用 Lucene,必須本身寫代碼去調用它的接口。bash

分詞說明

  • 搜索引擎在對數據構建索引時,須要進行分詞處理。

  • 分詞是指將一句話拆解成多個單字,這些字或詞即是這句話的關鍵詞。

  • Elasticsearch 不支持對中文進行分詞創建索引,須要配合擴展elasticsearch-analysis-ik來實現中文分詞處理。

3.集成Elasticsearch

3.1. Haystack介紹和安裝配置

  • Haystack 是在Django中對接搜索引擎的框架,搭建了用戶和搜索引擎之間的溝通橋樑。

    • 咱們在Django中能夠經過使用 Haystack 來調用 Elasticsearch 搜索引擎。

  • Haystack 能夠在不修改代碼的狀況下使用不一樣的搜索後端(好比 ElasticsearchWhooshSolr等等)。

Haystack安裝

$ pip install django-haystack
$ pip install elasticsearch==2.4.1複製代碼

Haystack註冊應用和路由

django的配置文件中註冊。

INSTALLED_APPS = [    'haystack', # 全文檢索註冊]​複製代碼

在總路由中新建haystack的路由。

urlpatterns = [url(r'^search/', include('haystack.urls')),]複製代碼

Haystack配置

  • 在配置文件中配置Haystack爲搜索引擎後端

# Haystack
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://192.168.103.158:9200/', # Elasticsearch服務器ip地址,端口號固定爲9200
        'INDEX_NAME': 'serach_mall', # Elasticsearch創建的索引庫的名稱
    },
}

# 當添加、修改、刪除數據時,自動生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 搜索的每頁大小
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 3複製代碼

HAYSTACK_SIGNAL_PROCESSOR 配置項保證了在Django運行起來後,有新的數據產生時,Haystack仍然可讓Elasticsearch實時生成新數據的索引。

3.2 Haystack創建數據索引

1.建立索引類
  • 經過建立索引類,來指明讓搜索引擎對哪些字段創建索引,也就是能夠經過哪些字段的關鍵字來檢索數據。

  • 本項目中對模型類SKU信息進行全文檢索,因此在該模型類的應用(goods)中新建search_indexes.py文件,用於存放索引類。索引類必須繼承haystack.indexes.SearchIndexhaystack.indexes.Indexable.

from haystack import indexes

from .models import SKU


class SKUIndex(indexes.SearchIndex, indexes.Indexable):
    """SKU索引數據模型類"""
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        """返回創建索引的模型類"""
        return SKU

    def index_queryset(self, using=None):
        """返回要創建索引的數據查詢集"""
        return self.get_model().objects.filter(is_launched=True) 複製代碼
  • 索引類SKUIndex說明:

    • SKUIndex創建的字段,均可以藉助HaystackElasticsearch搜索引擎查詢。

    • 其中text字段咱們聲明爲document=True,表名該字段是主要進行關鍵字查詢的字段。

    • text字段的索引值能夠由多個數據庫模型類字段組成,具體由哪些模型類字段組成,咱們用use_template=True表示後續經過模板來指明。

2.建立text字段索引值模板文件

  • 在項目templates目錄中建立text字段使用的模板文件

  • 具體在templates/search/indexes/goods/sku_text.txt文件中定義,其中goods爲應用名,sku_text.txt中的sku爲模型類小寫。

{{ object.id }}
{{ object.name }}
{{ object.caption }}複製代碼
  • 模板文件說明:當將關鍵詞經過text參數名傳遞時

    • 此模板指明SKU的idnamecaption做爲text字段的索引值來進行關鍵字索引查詢。

3.手動生成初始索引

$ python manage.py rebuild_index複製代碼

第一次須要生成索引須要執行上述命令,後續會自動生成索引。

3.3 全文檢索測試

準備測試表單

  • 請求方法:GET

  • 請求地址:/search/

  • 請求參數:q

<div class="search_wrap fl">
    <form method="get" action="/search/" class="search_con">
        <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
        <input type="submit" class="input_btn fr" name="" value="搜索">
    </form>
    ...
    ...
</div>複製代碼

而後在templates/search/目錄下新建search.html接收和渲染全文檢索的結果.

3.4 渲染搜索結果

Haystack返回的數據包括:

  • query:搜索關鍵字

  • paginator:分頁paginator對象

  • page:當前頁的page對象(遍歷page中的對象,能夠獲得result對象)

  • result.objects: 當前遍歷出來的SKU對象。

<div class="main_wrap clearfix">
    <div class=" clearfix">
        <ul class="goods_type_list clearfix">
            {% for result in page %}
            <li>
                {# object取得纔是sku對象 #}
                <a href="/detail/{{ result.object.id }}/"><img src="{{ result.object.default_image.url }}"></a>																
                <h4><a href="/detail/{{ result.object.id }}/">{{ result.object.name }}</a></h4>
                <div class="operate">
                    <span class="price">¥{{ result.object.price }}</span>
                    <span>{{ result.object.comments }}評價</span>
                </div>
            </li>
            {% else %}
                <p>沒有找到您要查詢的商品。</p>
            {% endfor %}
        </ul>
        <div class="pagenation">
            <div id="pagination" class="page"></div>
        </div>
    </div>
</div>複製代碼

這裏Elasticsearch替咱們把django中的視圖函數寫了。

搜索頁分頁器

<div class="main_wrap clearfix">
    <div class=" clearfix">
        ......
        <div class="pagenation">
            <div id="pagination" class="page"></div>
        </div>
    </div>
</div>

<script type="text/javascript">
    $(function () {
        $('#pagination').pagination({
            currentPage: {{ page.number }},
            totalPage: {{ paginator.num_pages }},
            callback:function (current) {
                window.location.href = '/search/?q={{ query }}&page=' + current;
            }
        })
    });
</script>複製代碼

這裏使用的jquery.pagination.js接收要渲染的數據,固然也可使用其餘框架的分頁器或自定義的來接收。

相關文章
相關標籤/搜索