當用戶在搜索框輸入關鍵字後,咱們要爲用戶提供相關的搜索結果。能夠選擇使用模糊查詢like
關鍵字實現,可是 like 關鍵字的效率極低。查詢須要在多個字段中進行,使用 like 關鍵字也不方便,另外分詞的效果也不理想。javascript
全文檢索即在指定的任意字段中進行檢索查詢。html
全文檢索方案須要配合搜索引擎來實現。java
搜索引擎進行全文檢索時,會對數據庫中的數據進行一遍預處理,單獨創建起一份索引結構數據。python
索引結構數據相似字典的索引檢索頁,裏面包含了關鍵詞與詞條的對應關係,並記錄詞條的位置。jquery
搜索引擎進行全文檢索時,將關鍵字在索引數據中進行快速對比查找,進而找到數據的真實存儲位置。數據庫
實現全文檢索的搜索引擎,首選的是Elasticsearch
。apache
Elasticsearch 是用 Java 實現的,開源的搜索引擎。django
它能夠快速地儲存、搜索和分析海量數據。維基百科、Stack Overflow、Github等都採用它。後端
Elasticsearch
的底層是開源庫 Lucene。可是,無法直接使用 Lucene,必須本身寫代碼去調用它的接口。bash
分詞說明
搜索引擎在對數據構建索引時,須要進行分詞處理。
分詞是指將一句話拆解成多個單字 或 詞,這些字或詞即是這句話的關鍵詞。
Elasticsearch
不支持對中文進行分詞創建索引,須要配合擴展elasticsearch-analysis-ik
來實現中文分詞處理。
Haystack 是在Django中對接搜索引擎的框架,搭建了用戶和搜索引擎之間的溝通橋樑。
咱們在Django中能夠經過使用 Haystack 來調用 Elasticsearch
搜索引擎。
Haystack 能夠在不修改代碼的狀況下使用不一樣的搜索後端(好比 Elasticsearch
、Whoosh
、Solr
等等)。
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實時生成新數據的索引。
1.建立索引類
經過建立索引類,來指明讓搜索引擎對哪些字段創建索引,也就是能夠經過哪些字段的關鍵字來檢索數據。
本項目中對模型類SKU信息進行全文檢索,因此在該模型類的應用(goods)中新建search_indexes.py
文件,用於存放索引類。索引類必須繼承haystack.indexes.SearchIndex
與haystack.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
創建的字段,均可以藉助Haystack
由Elasticsearch
搜索引擎查詢。
其中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的id
、name
、caption
做爲text
字段的索引值來進行關鍵字索引查詢。
3.手動生成初始索引
$ python manage.py rebuild_index複製代碼
第一次須要生成索引須要執行上述命令,後續會自動生成索引。
準備測試表單
請求方法: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
接收和渲染全文檢索的結果.
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
接收要渲染的數據,固然也可使用其餘框架的分頁器或自定義的來接收。