文章目录
- 一、Docker安装与运行
- 1.安装
- 2. 卸载
- 3. 安装镜像
- 二、elasticsearch安装与运行
- 1.安装
- 2. 配置项目信息
- 三、文章搜索功能实现
- 1. 索引库设计
- 2. urls.py配置
- 3. views.py逻辑处理
- 4. html填充
文章搜索使用elasticseach对需要进行查询的数据先进行预处理后,单独建立一份新的索引数据结构,比使用数据库带的like模糊查询的效率高非常多。
要使用elasticseach需要在docker上进行启动。
一、Docker安装与运行
Docker具体安装步骤和详细解释Docker官网上有明确的说明
1.安装
- 更新yum安装源
yum update
- 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
- 安装存储库
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
- 安装docker
yum install docker-ce
- 启动docker,并将其设置为开机启动
systemctl start docker
chkconfig docker on
- 试运行看是否安装成功
docker run hello-world
2. 卸载
- 载Docker软件包
yum remove docker-ce
- 主机上的映像,容器,卷或自定义配置文件不会自动删除。要删除所有图像,容器和卷:
rm -rf /var/lib/docker
3. 安装镜像
- 在docker仓库里面查找镜像
docker search + 镜像名 # 在仓库里面查找镜像
- 安装镜像
docker pull + 镜像名 # 安装镜像
docker images # 查看docker镜像信息
- 创建容器
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 # 查看版本
- 退出容器
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.安装
- 使用WinSCP将本地的elasticsearch-ik-2.4.6_docker.tar上传到阿里云中
/usr/local/ # 将elasticsearch-2.4.6放到这个文件目录下面
- 进入到config中修改elasticsearch.yml
cd /usr/local/elasticsearch-2.4.6/config/vim elasticsearch.yml
- 修改elasticsearch.yml中的network.host
# network.host: 192.168.216.137 原始IP
network.host: xxxxxxx # 这里改为阿里云里面的私IP
- 加载镜像
docker load -i elasticsearch-ik-2.4.6_docker.tar
- 创建容器
docker run -dti --name=elasticsearch -p 9200:9200 delron/elasticsearch-ik:2.4.6-1.0
- 安装依赖包
pip3 install django-haystack # 安装django-haystack
pip3 install elasticsearch==2.4.1 # 安装elasticsearch==2.4.1
pip freeze # 查看安装了哪些软件
- 一些指令
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填充
- 分页自定义模板标签
在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
- 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>