python-django框架中使用docker和elasticsearch配合實現搜索功能

注意:系統環境爲Ubuntu18css

1、docker安裝html

  0:若是以前有安裝過docker使用如下命令卸載:前端

sudo apt-get remove docker docker-engine docker.io containerd runc

  docker安裝官網參考:python

https://docs.docker.com/install/linux/docker-ce/ubuntu/linux

  1:首先更新aptdocker

sudo apt-get update

  2:添加證書安裝包以容許apt經過HTTPS:shell

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

  3:添加docker官方密鑰數據庫

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

  4:添加倉庫django

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

  5:安裝docker ceubuntu

sudo apt-get install docker-ce docker-ce-cli containerd.io

  6:測試

sudo docker run hello-world

  7:添加當前系統用戶到docker用戶組

sudo usermod -aG docker 用戶名  

 

docker 拓展命令:

  docker images :查看全部啓動成功的鏡像

  docker ps -a :查看全部

  docker logs 容器id :查看容器日誌 

  docker 若是啓動容器失敗,就先刪除容器,刪除目錄,再次執行安裝。

 

2、使用docker安裝Elasticsearch

1:獲取鏡像

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

 若是pull拉取很慢能夠從個人百度雲中下載,而後傳到Linux系統中而後使用docker命令導入

連接:https://pan.baidu.com/s/1zXBR_uHSFxK5xNxklGV1pQ
提取碼:96iw  

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

 查看本地倉庫是否有這個鏡像

docker images
或
docker image ls

  將下載的elasticsearch.zip上傳到Linux系統中的家目錄,而後解壓。在目錄中的elasticsearch/config/elasticsearch.yml第54行更改IP地址爲0.0.0.0,端口改成8002,默認爲9002

  解壓命令:

unzip elasticsearch.zip

 

2:建立docker容器並運行

 根據拉取到本地的鏡像建立容器,須要將elasticsearch/config配置文件所在目錄修改成你本身的路徑

docker run -dti --network=host --name=elasticsearch -v /home/上面上傳後解壓出來的文件路徑地址/elasticsearch/config:/usr/share/eleaticsearh/config delron/elasticsearch-ik:2.4.6-1.0

  查看是否建立成功,若是STATUS爲Up則建立成功

docker container ls -a 或 docker ps -a

  

 測試 curl 127.0.0.1:8002

 

3:進入項目的虛擬環境中,安裝如下包

pip install django-haystack
pip install elasticsearch==2.4.1

  

4:在django項目配置,在settings.py文件中加入下面配置。

4-1:在INSTALLED_APPS節點中註冊haystack

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

4-2:加入配置 

# 創建鏈接
ELASTICSEARCH_DSL = {
  'default':{
    'host':'127.0.0.1:8002'  
  },
}
# 配置Haystack HAYSTACK_CONNECTIONS = { 'default': { 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', 'URL': 'http://127.0.0.1:8002/', # 此處爲elasticsearch運行的服務器ip地址,端口號固定爲9200 'INDEX_NAME': 'mysite', # 指定elasticsearch創建的索引庫的名稱 }, } # 當添加、修改、刪除數據時,自動生成索引,當數據庫改變時候,會自動更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor' 
# 每頁顯示多少條數據
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 20

 

5:創建索引

 在須要建立索引的實體中建立search_indexes.py(文件名固定寫法)

  

5-1:search_indexes.py文件內容以下:

 

from haystack import indexes
from .models import News  # 導入模型類


# 建索引類
# 模型名稱+Index(固定的)
class NewsIndex(indexes.SearchIndex, indexes.Indexable):
    '''
    News索引數據庫模型
    '''
    # 這個主要是使用5-2來創建索引
    text = indexes.CharField(document=True, use_template=True)
    # 如下是爲了在使用時 news.id 若是沒有寫就須要news.object.id
    id = indexes.IntegerField(model_attr='id')
    title = indexes.CharField(model_attr='title')
    digest = indexes.CharField(model_attr='digest')
    content = indexes.CharField(model_attr='content')
    image_url = indexes.CharField(model_attr='image_url')

    def get_model(self):
        '''
        返回創建索引模型
        '''
        return News

    def index_queryset(self, using=None):
        '''
        返回要創建索引的數據查詢集
        :param using:
        :return:
        '''

        return set.get_model().objects.filter(is_delete=False, tag_id=1)
        # return set.get_model().objects.filter(is_delete=False,tag_id=[1,2,3,4,5])

  

5-2:建立模板

# 須要在templates文件夾中建立一個search/indexes/app名稱/模型名稱小寫_text.txt文件(固定結構)

  

news_text.txt內容爲:須要創建的索引

 

6:生成索引

經過xshell進入項目進入虛擬環境執行

python manage.py rebuild_index

  

 

7: 分頁搜索接口/方法

7-1

from haystack.views import SearchView as _SearchView
from .models import News  # 導入模型類
from .models import HotNews
from mysite import setttings
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render
from django.views import View


class SearchView(_SearchView):
    # 模板文件
    template = 'news/search.html'

    # 重寫響應方式,若是請求參數爲空,返回模型News的熱門新聞數據,不然根據參數q搜索相關數據
    def create_response(self):
        kw = self.request.GET.get('q', '')
        if not kw:
            show_all = True
            hot_news = HotNews.objects.select_related(
                'News'
            ).only(
                'news__title',
                'news__image_url',
                'news__id'
            ).filter(
                is_delete=False
            ).order_by(
                'priority',
                '-news__clicks'
            )
            paginator = Paginator(hot_news, setttings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
            try:
                page = paginator.page(int(self.request.GET.get('page', 1)))
            except PageNotAnInteger:
                # 若是參數page的數據類型不是整數,則返回第一頁數據
                page = paginator.page(1)
            except EmptyPage:
                # 用戶訪問的頁數大於實際的頁數,則返回最後一頁的數據
                page = paginator.page(paginator.num_pages)
            return render(self.request, self.template, locals())
        else:
            show_all = False
            qs = super(SearchView, self).create_response()
            return qs

7-2:在app中的urls中設置url 

path('search/',view.SearchView(),name='search')

7-3:前端部分代碼

         <div class="content">
                    <!-- search-list start -->
                    {% if not show_all %}
                        <div class="search-result-list">
                            <h2 class="search-result-title">
                                搜索結果 <span style="font-weight: 700;color: #ff6620;">{{ paginator.num_pages }}</span>頁
                            </h2>
                            <ul class="news-list">
                                {% for one_news in page.object_list %}
                                    <li class="news-item clearfix">
                                        <a href="{% url 'news:detail' one_news.id %}" class="news-thumbnail"
                                           target="_blank">
                                            <img src="{{ one_news.object.image_url }}">
                                        </a>
                                        <div class="news-content">
                                            <h4 class="news-title">
                                                <a href="{% url 'news:detail' one_news.id %}">
                                                    {% highlight one_news.title with query %}
                                                </a>
                                            </h4>
                                            <p class="news-details">{% highlight one_news.digest with query %}</p>
                                            <div class="news-other">
                                                <span class="news-type">{{ one_news.object.tag.name }}</span>
                                                <span class="news-time">{{ one_news.object.update_time }}</span>
                                                <span
                                                        class="news-author">{% highlight one_news.object.author.username with query %}

                                      </span>
                                            </div>
                                        </div>
                                    </li>
                                {% endfor %}


                            </ul>
                        </div>

                    {% else %}

                        <div class="news-contain">
                            <div class="hot-recommend-list">
                                <h2 class="hot-recommend-title">熱門推薦</h2>
                                <ul class="news-list">

                                    {% for one_hotnews in page.object_list %}

                                        <li class="news-item clearfix">
                                            <a href="#" class="news-thumbnail">
                                                <img src="{{ one_hotnews.news.image_url }}">
                                            </a>
                                            <div class="news-content">
                                                <h4 class="news-title">
                                                    <a href="{% url 'news:detail' one_hotnews.news.id %}">{{ one_hotnews.news.title }}</a>
                                                </h4>
                                                <p class="news-details">{{ one_hotnews.news.digest }}</p>
                                                <div class="news-other">
                                                    <span class="news-type">{{ one_hotnews.news.tag.name }}</span>
                                                    <span class="news-time">{{ one_hotnews.update_time }}</span>
                                                    <span class="news-author">{{ one_hotnews.news.author.username }}</span>
                                                </div>
                                            </div>
                                        </li>

                                    {% endfor %}

                                </ul>
                            </div>
                        </div>

                    {% endif %}

                    <!-- search-list end -->
                    <!-- news-contain start -->

                    {# 分頁導航 #}
                    <div class="page-box" id="pages">
                        <div class="pagebar" id="pageBar">
                            <a class="a1">{{ page.paginator.count }}條</a>
                            {# 上一頁的URL地址 #}
                            {% if page.has_previous %}
                                {% if query %}
                                    <a href="{% url 'news:search' %}?q={{ query }}&page={{ page.previous_page_number }}"
                                       class="prev">上一頁</a>
                                {% else %}
                                    <a href="{% url 'news:search' %}?page={{ page.previous_page_number }}" class="prev">上一頁</a>
                                {% endif %}
                            {% endif %}
                            {# 列出全部的URL地址 #}
                            {% for num in page.paginator.page_range|slice:":10" %}
                                {% if num == page.number %}
                                    <span class="sel">{{ page.number }}</span>
                                {% else %}
                                    {% if query %}
                                        <a href="{% url 'news:search' %}?q={{ query }}&page={{ num }}"
                                           target="_self">{{ num }}</a>
                                    {% else %}
                                        <a href="{% url 'news:search' %}?page={{ num }}" target="_self">{{ num }}</a>
                                    {% endif %}
                                {% endif %}
                            {% endfor %}

                            {# 若是頁數大於10,則打兩點 #}
                            {% if page.paginator.num_pages > 10 %}
                                ..

                                {% if query %}
                                    <a href="{% url 'news:search' %}?q={{ query }}&page={{ page.paginator.num_pages }}"
                                       target="_self">{{ page.paginator.num_pages }}</a>
                                {% else %}
                                    <a href="{% url 'news:search' %}?page={{ page.paginator.num_pages }}"
                                       target="_self">{{ page.paginator.num_pages }}</a>
                                {% endif %}

                            {% endif %}

                            {# 下一頁的URL地址 #}
                            {% if page.has_next %}
                                {% if query %}
                                    <a href="{% url 'news:search' %}?q={{ query }}&page={{ page.next_page_number }}"
                                       class="next">下一頁</a>
                                {% else %}
                                    <a href="{% url 'news:search' %}?page={{ page.next_page_number }}"
                                       class="next">下一頁</a>
                                {% endif %}
                            {% endif %}
                        </div>
                    </div>

                    <!-- news-contain end -->
                </div>

  

7-4:高亮及分頁樣式

/* === current index start === */
#pages {
	padding: 32px 0 10px;
}

.page-box {
	text-align: center;
    /*font-size: 14px;*/
}

#pages a.prev, a.next {
	width: 56px;
	padding: 0
}

#pages a {
	display: inline-block;
	height: 26px;
	line-height: 26px;
	background: #fff;
	border: 1px solid #e3e3e3;
	text-align: center;
	color: #333;
	padding: 0 10px
}

#pages .sel {
	display: inline-block;
	height: 26px;
	line-height: 26px;
	background: #0093E9;
	border: 1px solid #0093E9;
	color: #fff;
	text-align: center;
	padding: 0 10px
}

.highlighted{
    color:coral;
    mso-ansi-font-weight: bold;
}
/* === current index end === */

  

8:效果圖

 

相關文章
相關標籤/搜索