zoukankan      html  css  js  c++  java
  • python-django框架中使用docker和elasticsearch配合实现搜索功能

    注意:系统环境为Ubuntu18

    一、docker安装

      0:如果之前有安装过docker使用以下命令卸载:

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

      docker安装官网参考:

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

      1:首先更新apt

    sudo apt-get update
    

      2:添加证书安装包以允许apt通过HTTPS:

    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:添加仓库

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

      5:安装docker ce

    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 如果启动容器失败,就先删除容器,删除目录,再次执行安装。

    二、使用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 {
    	 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:效果图

     

  • 相关阅读:
    手机摇一摇代码
    ftp
    .net 设置导航的当前状态
    app 尺寸
    繁简体 互转 js
    静态页分页效果
    判断浏览器
    python列表,元组,字典和字符串之间的相互转换
    uliweb框架数据库操作
    uliweb的模版
  • 原文地址:https://www.cnblogs.com/wendj/p/10979960.html
Copyright © 2011-2022 走看看