文章目录

  • 一、Docker安装与运行
  • 1.安装
  • 2. 卸载
  • 3. 安装镜像
  • 二、elasticsearch安装与运行
  • 1.安装
  • 2. 配置项目信息
  • 三、文章搜索功能实现
  • 1. 索引库设计
  • 2. urls.py配置
  • 3. views.py逻辑处理
  • 4. html填充

文章搜索使用elasticseach对需要进行查询的数据先进行预处理后,单独建立一份新的索引数据结构,比使用数据库带的like模糊查询的效率高非常多。

要使用elasticseach需要在docker上进行启动。

一、Docker安装与运行

Docker具体安装步骤和详细解释Docker官网上有明确的说明

1.安装
  1. 更新yum安装源
yum update
  1. 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
  1. 安装存储库
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  1. 安装docker
yum install docker-ce
  1. 启动docker,并将其设置为开机启动
systemctl start docker

chkconfig docker on
  1. 试运行看是否安装成功
docker run hello-world
2. 卸载
  1. 载Docker软件包
yum remove docker-ce
  1. 主机上的映像,容器,卷或自定义配置文件不会自动删除。要删除所有图像,容器和卷:
rm -rf /var/lib/docker
3. 安装镜像
  1. 在docker仓库里面查找镜像
docker search + 镜像名   # 在仓库里面查找镜像
  1. 安装镜像
docker pull + 镜像名    # 安装镜像

docker images  # 查看docker镜像信息
  1. 创建容器
docker run -dti --name + 自定义容器名 -p 虚拟机端口:容器端口 + 容器名  # 创建容器

docker ps  # 查看容器状态

docker ps -a # 查看所有容器状态

docker inspect id  # 根据容器id查看容器信息

docker inspect fae  # 查看容器信息

docker exec -it fae /bin/bash   进入到容器中

cat /etc/issue   # 查看版本
  1. 退出容器
ctrl + p  → ctrl + q  # 退出 :先按ctrl+p,再按ctrl+q; exit会退出整个系统

docker commit fae 自定义容器名:版本号  # 制作docker容器

docker save -o 自定义的容器名.tar 自定义容器名:版本号  # 打包镜像

docker image rm 路径地址  # 移除镜像

docker run -p 本机映射端口:镜像映射端口 -d  --name 启动镜像名称 -e 镜像启动参数  镜像名称:镜像版本号  # 启动镜像

二、elasticsearch安装与运行

1.安装
  1. 使用WinSCP将本地的elasticsearch-ik-2.4.6_docker.tar上传到阿里云中
/usr/local/  # 将elasticsearch-2.4.6放到这个文件目录下面
  1. 进入到config中修改elasticsearch.yml
cd /usr/local/elasticsearch-2.4.6/config/vim elasticsearch.yml
  1. 修改elasticsearch.yml中的network.host
# network.host: 192.168.216.137   原始IP

network.host: xxxxxxx  # 这里改为阿里云里面的私IP
  1. 加载镜像
docker load -i elasticsearch-ik-2.4.6_docker.tar
  1. 创建容器
docker  run -dti --name=elasticsearch -p 9200:9200 delron/elasticsearch-ik:2.4.6-1.0
  1. 安装依赖包
pip3 install django-haystack # 安装django-haystack

pip3 install elasticsearch==2.4.1 # 安装elasticsearch==2.4.1

pip freeze  # 查看安装了哪些软件
  1. 一些指令
python manage.py haystack_info   # 查看建立的索引信息

curl ‘47.105.220.203:9200/_cat/indices?v’ #查看索引列表信息,具体意义如下:

名称

health

status

index

pri

rep

docs.count

docs.deleted

store.size

pri.store.size

意思

健康程度

状态

索引名

分片

复制

文档个数

删除个数

大小

分片大小

具体

yellow

open

aly

5

1

628

0

9.4mb

9.4mb

curl -X GET ‘http://47.105.220.203:9200/_cluster/health?pretty’ # 查询集群健康状态

2. 配置项目信息

settings.py配置

# 1. 需要将haystack进行app注册

INSTALLED_APPS = [
    "haystack",
]

# 2.配置haystack库

HAYSTACK_CONNECTIONS = {
    "default": {
        "ENGINE": "haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine",
        "URL": 'http://172.31.245.61:9200/',  # elasticsearch.yml配置里设置的ip地址,端口默认为9200
        "INDEX_NAME": 'aly',    # 指定elasticsearch的索引库的名称 必须是小写,名字可以随便自己取
    },
}

三、文章搜索功能实现

在使用haystack时有很多需要注意的地方,具体的可以在源码中看。

1. 索引库设计

单独建立索引库时,需要在需要索引的app下面创建一个search_indexes.py,名字是固定的,如果要改名字的话,需要改其他参数,具体的将源码。将需要索引的字段放到该数据库表中

# search_indexes.py这个文件名时固定
from haystack import indexes
from news.models import Articles


class ArticlesIndex(indexes.SearchIndex, indexes.Indexable):
    """
    类名是索引的表名+Index构成

    """
    text = indexes.CharField(document=True, use_template=True)  # 允许使用数据模板
    id = indexes.IntegerField(model_attr="id")   # 数据表中的id
    title = indexes.CharField(model_attr="title")   # 数据表中的title
    digest = indexes.CharField(model_attr="digest")     # 数据表中的digest
    content = indexes.CharField(model_attr="content")   # 数据表中的content
    image_url = indexes.CharField(model_attr="image_url")   # 数据表中的image_url

    def get_model(self):
        """
        返回建立索引的模型类
        :return:
        """
        return Articles

    def index_queryset(self, using=None):
        """
        返回建立索引的数据的query集,去掉一部分不满足条件的文章
        :param using:
        :return:
        """
        return self.get_model().objects.filter(is_delete=False)
    
    	# 如果出现timeout超时的情况可以把return改为下面,少建立几个索引,这样不会超时,后面的进行更新
         return self.get_model().objects.filter(is_delete=False,tag_id__in=[1,2,3])

建立玩索引库后进行手动创建索引:进入到项目manage.py的目录下面

python manage.py rebuild_index # 手动创建索引

一些命令:

python manage.py --help  # 查询所有命令

python manage.py update_index  # 更新索引库

# 也可以在settings.py里面设置自动更新

# 当数据库改变时,会自动更新索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

手动从创建完索引库后,那么就是创建关键索引字段了,索引哪些字段:

templates/search/indexes/news(自己的app名)/articles_text.txt(表名小写_text.txt) 这些都是固定的。在articles_text.txt下面写上自己需要用来索引的字段

{{ object.title }}
{{ object.digest }}
{{ object.content }}
2. urls.py配置

news/urls.py

from django.urls import path
from news import views


app_name = "news"

urlpatterns = [
    path("search/", views.Search(), name="search")
]
3. views.py逻辑处理

news/views.py

from alyBlog import settings

from django.shortcuts import render
from haystack.views import SearchView
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

from news import models as _models


class Search(SearchView):

    template = 'news/search.html'

    def create_response(self):
       # 1.接收前端传来的查询值,默认为空
        keyword = self.request.GET.get('q','')
        
         # 2. 判断查询值是否为空
        if not keyword:
            show = True  # 设置标记
            
             # 3.为空就显示热门文章
            host_news = _models.HotArticle.objects.select_related('article').only('article_id','article__title',                                     'article__image_url').filter(is_delete=False).order_by('priority')
            
            # 4. 进行分页,HAYSTACK_SEARCH_RESULTS_PER_PAGE在settings.py设置
            paginator = Paginator(host_news, settings.HAYSTACK_SEARCH_RESULTS_PER_PAGE)
            try:
                page = paginator.page(int(self.request.GET.get('page',1)))
                
            # 5. 判断传的不是整数,设置page=1
            except PageNotAnInteger:
                page = paginator.page(1)
                
			# 5. 判断传值超过总页数:设置page最后一页
            except EmptyPage:
                page = paginator.page(paginator.num_pages)
            return render(self.request,self.template,locals())
        else:
            show = False   # 设置标记
            return super(Search, self).create_response()
4. html填充
  1. 分页自定义模板标签
    news/templatetags/page.py
from django import template

register = template.Library()


@register.filter()
def page_bar(page):
    page_list = []
    # 左边
    if page.number != 1:
        page_list.append(1)
    if page.number - 3 > 1:
        page_list.append('...')
    if page.number - 2 > 1:
        page_list.append(page.number - 2)
    if page.number - 1 > 1:
        page_list.append(page.number - 1)

    page_list.append(page.number)

    # 右边
    if page.paginator.num_pages > page.number + 1:
        page_list.append(page.number + 1)

    if page.paginator.num_pages > page.number + 2:
        page_list.append(page.number + 2)
    if page.paginator.num_pages > page.number + 3:
        page_list.append('...')
    if page.paginator.num_pages != page.number:
        page_list.append(page.paginator.num_pages)
    return page_list
  1. html
{% if not show %}
<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">

        {% load highlight %}

        {% for one_article in page.object_list %}
        <li class="news-item clearfix">
            <a href="{% url 'news:article_detail' one_article.id %}" class="news-thumbnail"
               target="_blank">
                <img src="{{ one_article.object.image_url }}" alt="">
            </a>
            <div class="news-content">
                <h4 class="news-title">
                    <a href="{% url 'news:article_detail' one_article.id %}">
                        {% highlight one_article.title with query %}
                    </a>
                </h4>
                <p class="news-details">{% highlight one_article.digest with query %}</p>
                <div class="news-other">
                    <a href=""><span class="news-type">{{ one_article.object.tag.name }}</span></a>
                    <span class="news-clicks">点击量({{ one_article.object.clicks }})</span>
                    <span class="news-time">{{ one_article.object.update_time }}</span>
                    <span class="news-author">
                        {% highlight one_article.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_hotarticle in page.object_list %}

            <li class="news-item clearfix">
                <a href="#" class="news-thumbnail">
                    <img src="{{ one_hotarticle.article.image_url }}">
                </a>
                <div class="news-content">
                    <h4 class="news-title">
                        <a href="{% url 'news:article_detail' one_hotarticle.article.id %}"
                           >{{ one_hotarticle.article.title }}</a>
                    </h4>
                    <p class="news-details">{{ one_hotarticle.article.digest }}</p>
                    <div class="news-other">
                        <span class="news-type">{{ one_hotarticle.article.tag.name }}</span>
                        <span class="news-clicks">点击量({{ one_hotarticle.article.clicks }})</span>
                        <span class="news-time">{{ one_hotarticle.article.update_time }}</span>
                        <span class="news-author">{{ one_hotarticle.article.author.username }}</span>
                    </div>
                </div>
            </li>
            {% endfor %}

        </ul>
    </div>
</div>
{% endif %}

{# 分页导航 #}
<div class="page-box" id="pages">
    <div class="pagebar" id="pageBar">
        <a class="a1">共 {{ page.paginator.count | default:0 }} 条</a>

        {# 上一页的URL地址#}
        {% if page.has_previous %}
        {% if query %}
        <a href="{% url 'news:search' %}?q={{ query }}&page={{ page.previous_page_number }}&q={{ query }}" class="prev">上一页</a>
        {% else %}
        <a href="{% url 'news:search' %}?page={{ page.previous_page_number }}" class="prev">上一页</a>
        {% endif %}
        {% endif %}


        {#列出所有的URL地址 页码#}
        {% if page.has_previous or page.has_next %}

        {% for num in page|page_bar %}
        {% if query %}
        {% if num == '...' %}
        <span class="point">{{ num }}</span>
        {% else %}
        {% if num == page.number %}
        <span class="sel">{{ num }}</span>
        {% else %}
        <a href="{% url 'news:search' %}?page={{ num }}&q={{ query }}">{{ num }}</a>
        {% endif %}
        {% endif %}
        {% else %}
        {% if num == '...' %}
        <span class="point">{{ num }}</span>
        {% else %}
        {% if num == page.number %}
        <span class="sel">{{ num }}</span>
        {% else %}
        <a href="{% url 'news:search' %}?page={{ num }}">{{ num }}</a>
        {% endif %}
        {% endif %}
        {% endif %}
        {% endfor %}
        {% endif %}

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