1. 程式人生 > >使用haystack實現Django的全文搜尋 -- Elasticsearch搜尋引擎

使用haystack實現Django的全文搜尋 -- Elasticsearch搜尋引擎

全文搜尋:

在使用python進行web開發的時候,免不了需要使用到全文搜尋;全文搜尋和我們平常使用的資料庫的模糊搜尋查詢不一樣,例如在mysql資料庫中,如果進行模糊查詢,比如 name like '%wang%'這一類的,效率是非常低的;而我們需求的全文搜尋,在效率方面要求是很高的,而且必須能夠對中文進行分詞處理。

haystack:

1.介紹:

全文搜尋的框架;Haystack是 BSD許可的,可以很好地與第三方應用程式配合使用,無需修改原始碼,並支援Solr, Elasticsearch, Whoosh和 Xapian四種全文搜尋引擎;也就是說,我們在使用Solr, Elasticsearch, Whoosh和 Xapian這四種搜尋引擎的時候,不需要直接對它們直接進行操作,直接通過操作這個haystack框架,就可以進行進行全文搜尋;可以讓你在不修改程式碼的情況下使用不同的搜尋後端。

haystack官網

2.使用:

在Django中使用haystack,可以通過 pip install django-haystack 即可;
當然,如果你的Django專案中,使用到 REST framework,那麼可以直接安裝 pip install drf-haystack

搜尋引擎 Elasticsearch

1. 介紹:

Elasticsearch官網
Elasticsearch中文學習文件

開源的 Elasticsearch 是目前全文搜尋引擎的首選。

它可以快速地儲存、搜尋和分析海量資料。維基百科、Stack Overflow、Github 都採用它。

Elasticsearch 的底層是開源庫 Lucene。但是,你沒法直接用 Lucene,必須自己寫程式碼去呼叫它的介面。Elastic 是 Lucene 的封裝,提供了 REST API 的操作介面,開箱即用。所有的功能被整合到一個服務裡面,你的應用可以通過簡單的RESTful API、各種語言的客戶端甚至命令列與之互動。

Elasticsearch 是用Java實現的,Elasticsearch 不支援對中文進行分詞建立索引,需要配合擴充套件elasticsearch-analysis-ik來實現中文分詞處理。

2.專案環境介紹:

注意:本文所介紹和使用的Elasticsearch是基於python和Django進行操作演練的。

  • 開發環境:
    python:3.5
    Django:1.11.11
    djangorestframework : 3.9.0
    django-haystack : 2.8.1
    Docker (由於使用的是python,這裡演練不準備使用Java,所以用docker來執行Elasticsearch映象的)

3.Elasticsearch 安裝 和 執行:

使用java執行Elasticsearch可以參考:
https://es.xiaoleilu.com/010_Intro/10_Installing_ES.html

我們這裡是使用映象在docker中執行,映象下載方式如下:

1.映象的獲取

1.1 可以通過網路pull

docker image pull delron/elasticsearch-ik:2.4.6-1.0

1.2 當然,可以直接下載我這邊提供的映象包:
連結: https://pan.baidu.com/s/1_9mQ9sFmGuPdcwBfHZ6Sxw
提取碼: yjee

 docker load -i elasticsearch-ik-2.4.6_docker.tar

此處注意版本:版本是2.4.6

2.配置

修改elasticsearch的配置檔案 elasticsearc-2.4.6/config/elasticsearch.yml第54行,更改ip地址為本機ip地址,比如:

network.host: 127.0.0.1

3.建立docker容器並進行執行

docker run -dti --network=host --name=elasticsearch -v /home/python/elasticsearch-2.4.6/config:/usr/share/elasticsearch/config delron/elasticsearch-ik:2.4.6-1.0

注意:-v 後面的對映路徑
/home/python/elasticsearch-2.4.6/config:指的是進行修改過的配置檔案存在的路徑;
/usr/share/elasticsearch/config delron/elasticsearch-ik:2.4.6-1.0:是映象檔案執行的路徑和版本;
檔案存放的位置不同,在進行對映的時候,是不一樣的

再一次開啟這個Elasticsearch映象時,直接可以使用:
docker container start Elasticsearch 即可

haystack與Elasticsearch對接:

Elasticsearch到這一步,已經是執行起來了,那麼我們如何來對其進行操作呢?
當然是使用我們haystack來進行對接;想要進行對接的話,除了之前安裝過的drf-haystack,還需要在python中安裝elasticsearch==2.4.1

1.基於python的客戶端的安裝:

pip install elasticsearch==2.4.1

這裡需要提醒的是,版本是需要特別注意的,如果在安裝的時候,後面不具體描述版本號,預設會下載最新的版本,但是相容問題有待提升,所以為了不必要的bug,可以按照我的版本進行對應。

2.配置
通過django的haystack來操作,所以在django中進行相關配置是必不可少的:

settings.py中新增下面的配置資訊:

1.應用註冊:

INSTALLED_APPS = [
    ...
    'haystack',
    ...
]

2.使用haystack需要進行的配置:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://127.0.0.1:9200/',  # 此處為elasticsearch執行的伺服器ip地址,埠號固定為9200
        'INDEX_NAME': 'djangotest',  # 指定elasticsearch建立的索引庫的名稱
    },
}


#當新增、修改、刪除資料時,自動生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

HAYSTACK_SIGNAL_PROCESSOR 的配置保證了在Django執行起來後,有新的資料產生時,haystack仍然可以讓Elasticsearch實時生成新資料的索引;當然,而歐盟也是可以手動進行索引的生成:

python manage.py rebuid_index

3.索引的建立

1.索引檔案建立:
在子應用目錄下,新增一個索引,名為: search_indexes.py;
下面的程式碼在goods/search_indexes.py

from haystack import indexes
 ① # 修改此處,改成你自己的model
from goods.models import Goods    (Goods是子應用goods中的一個模型類) 

② #修改此處,類名為模型類的名稱+Index,比如模型類為Goods,則這裡類名為GoodsIndex
class GoodsIndex(indexes.SearchIndex, indexes.Indexable):
    # 指明哪些欄位產生索引,產生索引的欄位,會作為前端檢索查詢的關鍵字;
    # document是指明text是使用的文件格式,產生欄位的內容在文件中進行描述;
    # use_template是指明在模板中被宣告需要產生索引;
    text = indexes.CharField(document=True, use_template=True)

③ # 此外可以存在,可以不存在,看具體需要的資料
    """下面這些欄位,在索引類中進行申明,在REST framework中,索引類的欄位可以被作為索引查詢結果返回資料額來源"""
    id = indexes.IntegerField(model_attr='id')
    name = indexes.CharField(model_attr='name')
    price = indexes.DecimalField(model_attr='price')

    """也就是說,前端在索引的時候,可以按照text=xxx,也可以按照id=xxx,name=xxx等,我們的資料返回也是返回id,name,price """

④ # 修改此處,返回的是你自己的model
    def get_model(self):
        """獲取模型類"""
        return Goods
        
⑤# 修改return 可以修改返回查詢集的內容,比如返回時,有什麼條件限制的時候
    def index_queryset(self, using=None):
        """宣告滿足索引要求的返回的查詢集"""
        return Goods.objects.all()

說明:
1.在進行索引類的使用時,修改上述程式碼中的①②③④⑤即可;
2.此檔案指定如何通過已有資料來建立索引。get_model處,直接將django中的model放過來,便可以直接完成索引啦,無需關注資料庫讀取、索引建立等細節。
3.text=indexes.CharField一句,指定了將模型類中的哪些欄位建立索引,而use_template=True說明後續我們還要指定一個模板檔案,告知具體是哪些欄位;

2.指定索引使用的模板檔案/指名需要建立索引的欄位:

在專案的“templates/search/indexes/應用名稱/”下建立“模型類名稱_text.txt”檔案
比如:
templates/search/indexes/goods/sku_text.txt:
這個是模板檔案的路徑,此檔案指定將模型中的哪些欄位建立索引
indexes: 用於索引; 
goods: 有索引的子應用名稱; 
sku_text: sku是指明那個模型類,text是指明那個欄位
在這裡插入圖片描述
檔案中寫入的內容如下:

{{ object.欄位1 }}
{{ object.欄位2 }}
{{ object.欄位3 }}

3.檢視函式和序列化器:

(下面的檢視函式和序列化器,如果你沒有使用REST Framework,直接使用的Django話,那麼可以直接寫django中的檢視函式,進行請求和響應資料的處理)

RESTFramewirk中的haystack中提供了相應的檢視集和序列化器,可以直接進行使用:

建立haystack序列化器

from drf_haystack.serializers import HaystackSerializer

class GoodsIndexSerializer(HaystackSerializer):
    """
    Goods索引結果資料序列化器
    """
    class Meta:
        index_classes = [GoodsIndex]
        fields = ('text', 'id', 'name', 'price')

注意fields屬性的欄位名與GoodsIndex類的欄位對應;

建立檢視

from drf_haystack.viewsets import HaystackViewSet

class GoodsSearchViewSet(HaystackViewSet):
    """
    Goods搜尋
    """
    index_models = [Goods]

    serializer_class = GoodsIndexSerializer

4.路由

路由(檢視函式用的是檢視集,所以通過下面的方式新增路由):

from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('skus/search', views.SKUSearchViewSet, base_name='skus_search')
urlpatterns += router.urls